GeoProcess Consumer-Sample
Introdução
Enquanto o Consumer-Basic tem como objetivo ser uma referência básica para o desenvolvimento de consumidores, o Consumer-Sample busca servir como uma base rica em exemplos para o desenvolvimento de diferentes objetos de resposta. Ele funciona como um super consumidor para demonstrar e exemplificar as principais funcionalidades disponíveis na plataforma GeoProcess.
A ideia por trás do Consumer-Sample é utilizá-lo como um sistema de consulta para a implementação de consumidores voltados a propósitos específicos em qualquer projeto.
Questões Importantes para o Desenvolvimento de Consumidores
Antes de iniciar o desenvolvimento de um consumidor, é essencial considerar algumas questões:
- Quais perguntas o consumidor será capaz de responder?
- Quantas perguntas o consumidor irá abordar?
- Quais são os parâmetros de entrada necessários para cada pergunta?
- Quais bases de dados serão utilizadas para as respostas?
- Como as informações serão exibidas no dashboard?
Responder a essas questões é um passo fundamental para estruturar a implementação do consumidor.
Objetivo do Consumer-Sample
Os exemplos fornecidos no Consumer-Sample são projetados com o propósito didático, permitindo explorar e demonstrar as capacidades da plataforma de maneira prática e acessível. A seguir, apresentamos uma visão geral do módulo Consumer-Sample e como ele pode ser utilizado.
Visão Geral
A estrutura com as pastas e arquivos principais do projeto Consumer-Sample está destacada a seguir.

Na raiz do projeto também uma pasta chamada consumer em que fica localizado o módulo consumidor, nesse exemplo o módulo sampleworker.py.
Na raiz do projeto tem também um arquivo de configuração chamado questions.json que define uma série de configurações sobre o consumidor.
Na raiz do projeto tem também dois arquivos de configuração importante são: env_sample.conf e env.conf.
Por fim, na raiz do projeto tem uma pasta chamada tests em que ficam localizados os testes de software.
A seguir será detalhado alguns dos principais arquivos, módulos e diretórios do consumidor sample (exemplo).
Módulo consumer/sampleworker.py
Na raiz do projeto, existe um pacote/pasta chamado consumer que contém o código do consumidor com diversos exemplos implementados. Dentro deste pacote temos o módulo sampleworker.py. Neste módulo, temos a declaração de uma classe chamada SampleWorker que herda de Worker (definida na biblioteca PGST-LIB). Essa classe contém diversos exemplos de perguntas que o consumidor consegue responder de forma a ilustrar o potencial da plataforma GeoProcess.
A seguir temos uma visão geral de alguns métodos da classe SampleWorker.
class SampleWorker(Worker):
...
@process(name="Answer 1", questionId="Q1")
def process1(self, answer_request):
...
@process(name="Answer 2", questionId="Q2")
def process2(self, answer_request):
...
@process(name="Answer 3", questionId="Q3")
def process3(self, answer_request):
...
...
@process(name="Answer N", questionId="QN")
def processN(self, answer_request):
...
No código acima, podemos perceber que essa classe possui alguns métodos principais que são: process1, process2, process3 e processN. Cada um desses métodos de processamento são responsáveis por responder a uma pergunta do consumidor. Em que, o método processN responde a enésima pergunta. Farei uma explicação detalhada de cada um desses métodos.
Detalhando process1
O método process1 representa o processamento da primeira pergunta do consumidor e retorna a resposta a essa pergunta.
Objetivo
O objetivo dessa pergunta é mostrar como realizar plots de gráficos. Para essa demonstração cinco gráficos diferentes foram plotados utilizando dois métodos diferentes (addChart e addChartPlotly).
A seguir vemos a implementação do método process1.
Informação
Esta é uma pergunta de exemplo e não utiliza nenhum banco de dados.
Nessa implementação temos a modelagem de uma pergunta e os elementos que compõem a resposta. Esse método (process1) possui um decorador @process com os parâmetros name e questionId da pergunta (linha 1). Este método recebe apenas um parâmetro com nome answer_request que é um dicionário (json) com os parâmetros de entrada (linha 2). Nesse exemplo em específico, nenhum parâmetro de entrada é necessário, assim essa variável não é utilizada. A primeira ação do método é imprimir no sistema de log uma informação indicando que a pergunta já começou a ser processada. No início é declarado um objeto chamado answer do tipo Answer que irá armazenar a resposta (linha 4). Na resposta temos a adição um gráfico de colunas (linhas 5-8). Em seguida, temos a inclusão de um gráfico de pizza (linhas 9-13). Esses dois gráficos foram plotados utilizando o método addChart. Nas linhas 14 a 19, temos a declaração de um dicionário que será utilizado para plotar um gráfico de barras. Na linha 20, temos a função que plota o gráfico de barras utilizando a biblioteca Plotly. Nas linhas 22 a 28, temos a inclusão de dois outros gráficos utilizando a biblioteca Plotly só que com os dados carregados de um arquivo. Esses três últimos gráficos utilizaram o método addChartPlotly. No final, é adicionado uma mensagem informando o status da pergunta (linha 30). Por fim, é retornado o objeto com a resposta (linha 32).
Gráfico com Plotly:
- Um dicionário
dataé criado com parâmetros específicos para um gráfico de barras usando a biblioteca Plotly, configurando tanto os dados quanto o layout (linhas 9 a 14). O gráfico é adicionado aoanswerna linha 15.
O método addChartPlotly permite a adição de um gráfico usando a biblioteca Plotly. Abaixo estão a assinatura do método (também definida em PGST-LIB) e um exemplo conforme o código acima. Note que os dois primeiros parâmetros são obrigatórios e os parâmetros adicionais são opcionais.
Após executar a primeira pergunta da aplicação consumidora, uma resposta visual semelhante a imagem a seguir será mostrada.



Detalhando process2
O método process2 representa o processamento da segunda pergunta do consumidor e retorna a resposta a essa pergunta.
Objetivo
O objetivo dessa pergunta é mostrar como realizar a leitura de uma determinada tabela do Banco de Dados. Sobre esses dados são realizados alguns filtros, então alguns gráficos e tabelas são exibidos no dashboard. Os gráficos e tabelas contém informações sobre estados e municípios.
A seguir vemos a implementação do método process2.
Informação
Para a execução desse consumidor com essa pergunta é necessário ter no banco de dados uma tabela chamada br_uf_2022 e br_municipios_2022.
Nessa implementação temos a modelagem de uma pergunta e os elementos que compõem a resposta. Esse método (process2) possui um decorador @process com os parâmetros name e questionId da pergunta (linha 1). Este método recebe apenas um parâmetro com nome answer_request que é um dicionário (json) com os parâmetros de entrada (linha 2). No início é declarado um objeto chamado answer do tipo Answer que irá armazenar a resposta (linha 4). Nas linhas 5 a 8, são feitos as leituras dos parâmetros de entrada da aplicação. A linha 10 mostra o código SQL que irá buscar os campos sigla_uf e area_km2 da tabela br_uf_2022. A linha 11 executa essa instrução SQL e pega todos os resultados. Na linha 13, os dados são ordenados de acordo com a área em quilometros quadrados. Na linha 14, um filtro com os N menores estados é feito. A linha 15, pega a resposta que antes estava organizado em uma lista de tuplas e armazena o resultado em duas listas distintas (estados e area). Na linha 16, um gráfico é adicionado. As linhas subsequentes do código são semelhantes as anteriores analizadas e são consideradas intuitivas.
Exemplo de parâmetro de entrada no arquivo answerRequest.json:
...
"data": {
"qtd_uf_menores": 5,
"qtd_uf_maiores": 5,
"qtd_mun_menores": 50,
"qtd_mun_maiores": 50
}
A entrada do método são quatro valores inteiros que serão utilizados para filtrar as buscas na tabela de estados e na tabela de municípios.
Após executar a segunda pergunta da aplicação consumidora, uma resposta visual semelhante a imagem a seguir será mostrada.





Detalhando process3
O método process3 representa o processamento da terceira pergunta do consumidor e retorna a resposta a essa pergunta.
Objetivo
O objetivo dessa pergunta é realizar a busca por um código de imóvel na tabela area_imovel e verificar se existem interseções entre esse imóvel e alguma área da tabela area_de_quilombolas e terras_indigenas. Caso exista intersseção, então um mapa, um gráfico e uma tabela com as áreas intersectadas serão exibidos detalhando o resultado.
A seguir vemos a implementação do método process3.
Informação
Para a execução desse consumidor com essa pergunta é necessário ter no banco de dados uma tabela chamada area_imovel, area_de_quilombolas e terras_indigenas.
Nessa implementação temos a modelagem de uma pergunta e os elementos que compõem a resposta. Esse método (process3) possui um decorador @process com os parâmetros name e questionId da pergunta (linha 1). Este método recebe apenas um parâmetro com nome answer_request que é um dicionário (json) com os parâmetros de entrada (linha 2). No início é declarado um objeto chamado answer do tipo Answer que irá armazenar a resposta (linha 4). Na linha 5, uma leitura do código do imóvel é feita. Esse é o código que será utilizado na nossa operação de busca. A linha 6 retorna a propriedade que possui o código do imóvel passado como parâmetro. A linha 7 verifica se esse imóvel existe na base de dados. A linha 8 adiciona essa propriedade no mapa do dashboard. A linha 9 chama um método para verificar interseção entre a propriedade pesquisada e uma área qualquer na tabela area_de_quilombolas. Caso exista interseção, então a área é adicionada ao mapa (linha 35) e uma tabela é adicionada (linha 36). Na linha 20, é adicionado um gráfico com todas as áreas das camadas que intersectam com a área do imóvel.
Exemplo de parâmetro de entrada no arquivo answerRequest.json:
A entrada do método é um código do imóvel que será utilizado para buscar um terreno na tabela area_imovel.
Após executar a terceira pergunta da aplicação consumidora, uma resposta visual semelhante a imagem a seguir será mostrada.


Detalhando process4
O método process4 representa o processamento da quarta pergunta do consumidor e retorna a resposta a essa pergunta.
Objetivo
O objetivo dessa pergunta é realizar uma busca por uma área selecionada. Essa busca visa retornar todas as áreas das camadas area_imovel, area_de_quilombolas e terras_indigenas que intersectam com a área selecionada.
A resposta da pergunta contém apenas um mapa com todas as áreas que possuem interseção com a região.
A seguir vemos a implementação do método process4.
Informação
Para a execução desse consumidor com essa pergunta é necessário ter no banco de dados uma tabela chamada area_imovel, area_de_quilombolas e terras_indigenas.
Nessa implementação temos a modelagem de uma pergunta e os elementos que compõem a resposta. Esse método (process4) possui um decorador @process com os parâmetros name e questionId da pergunta (linha 1). Este método recebe apenas um parâmetro com nome answer_request que é um dicionário (json) com os parâmetros de entrada (linha 2). No início é declarado um objeto chamado answer do tipo Answer que irá armazenar a resposta (linha 4). Na linha 5, uma leitura da área selecionada pelo usuário é feita. Essa é a área que será utilizado na nossa operação de busca. A linha 6 adiciona essa área selecionada no mapa do dashboard. A linha 7 transforma a área em um objeto do tipo MultiPolygon. A linha 8 verifica se existe cruzamento entre a área selecionada e a tabela area_imovel. A linha 10 adiciona as áreas que cruzam com a área selecionda, caso existam. As linhas subsequentes são similares as anteriormente explicadas.
Exemplo de parâmetro de entrada no arquivo answerRequest.json:
"data": {
"map": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
[
-52.79853429987142,
-26.668723440791226
],
[
-52.79853429987142,
-27.722008785135223
],
[
-50.72010819942622,
-27.722008785135223
],
[
-50.72010819942622,
-26.668723440791226
],
[
-52.79853429987142,
-26.668723440791226
]
]
],
"type": "Polygon"
}
}
]
}
}
A entrada do método é uma área de busca (selecionada pelo usuário) que será utilizada para buscar imóveis (area_imovel), área de quilombolas (area_de_quilombolas), e terras indígenas (terras_indigenas) dentro da área especificada/selecionada.
Após executar a quarta pergunta da aplicação consumidora, uma resposta visual semelhante a imagem a seguir será mostrada.

Detalhando process5
O método process5 representa o processamento da quinta pergunta do consumidor e retorna a resposta a essa pergunta.
Objetivo
O objetivo dessa pergunta é realizar uma busca por código da cidade. Essa busca visa retornar todas as áreas das camadas assentamentos_brasil e terras_indigenas que intersectam com a cidade especificada.
A resposta da pergunta contém apenas um mapa com todas as áreas que possuem interseção com a cidade.
A seguir vemos a implementação do método process5.
Informação
Para a execução desse consumidor com essa pergunta é necessário ter no banco de dados uma tabela chamada br_municipios_2022, assentamentos_brasil e terras_indigenas.
Nessa implementação temos a modelagem de uma pergunta e os elementos que compõem a resposta. Esse método (process5) possui um decorador @process com os parâmetros name e questionId da pergunta (linha 1). Este método recebe apenas um parâmetro com nome answer_request que é um dicionário (json) com os parâmetros de entrada (linha 2). No início é declarado um objeto chamado answer do tipo Answer que irá armazenar a resposta (linha 4). Na linha 5, uma leitura do código da cidade é realizada. Esse é o código que será utilizado na nossa operação de busca. A linha 6 obtem a cidade a partir do código da cidade. Essa busca é feita na tabela br_municipios_2022. A linha 8 verifica se a cidade passada é valida. A linha 9 adiciona ao mapa a área da cidade. A linha 10 pega o parâmetro que verifica se iremos analisar a interseção com a camada assentamentos_brasil. A linha 12 verifica se existe interseção entre a cidade e alguma área na tabela assentamentos brasil. Se existir na linha 14 é adicionado essa área no mapa. As linhas subsequentes são similares as anteriormente explicadas.
Exemplo de parâmetro de entrada no arquivo answerRequest.json:
A entrada do método é um código de cidade (nesse exemplo, o código 1500602 corresponde a cidade de Altamira - PA) que será utilizado para buscar na tabela (br_municipios_2022). Dois outros parâmetros são necessários e representam valores lógicos indicando se tais tabelas (layer_assentamentos_brasil e layer_terras_indigenas) estarão na análise de interseção com o código da cidade.
Após executar a quinta pergunta da aplicação consumidora, uma resposta visual semelhante a imagem a seguir será mostrada.

Detalhando process6
O método process6 representa o processamento da sexta pergunta do consumidor e retorna a resposta a essa pergunta.
Objetivo
O objetivo dessa pergunta é mostrar como gerar relatórios em PDF e KML. Assim, a aplicação mostra um mapa com uma área selecionada, dois gráficos e uma tabela simples. Dessa maneira, foca-se na geração do relatório. Serão gerados um relatório em PDF e um relatório em KML com a área selecionada.
A seguir vemos a implementação do método process6.
Informação
Esta é uma pergunta de exemplo e não utiliza nenhum banco de dados.
Nessa implementação temos a modelagem de uma pergunta e os elementos que compõem a resposta. Esse método (process6) possui um decorador @process com os parâmetros name e questionId da pergunta (linha 1). Este método recebe apenas um parâmetro com nome answer_request que é um dicionário (json) com os parâmetros de entrada (linha 2). No início é declarado um objeto chamado answer do tipo Answer que irá armazenar a resposta (linha 4). Na linha 5, uma leitura da área do mapa selecionada e feita. Na linha 6, uma leitura do valor lógico se irá ter ou não relatório é realizada. A linha 7 adiciona no mapa a área especificada/selecionada pelo usuário. As linhas 8 até 16 adicionam dois gráficos. As linhas 17 até 20 adicionam uma tabela. A linha 21 adiciona uma mensagem na resposta. A linha 22 verifica se irá ter geração de relatório. As linhas 23 até 39 especificam os parâmetros do relatório. Dois relatórios serão gerados, um em formato PDF chamado report.pdf e um em formato KML chamado area.kml. Se o relatório KML ultrapassar o limite de 5 MB então será feito uma compactação do arquivo de resposta em um arquivo chamado data.zip. A linha 40 adiciona em forma de corrente (chain) a geração do relatório. Por fim, a linha 42 retorna a resposta.
Exemplo de parâmetro de entrada no arquivo answerRequest.json:
"data": {
"map": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
[
-52.79853429987142,
-26.668723440791226
],
[
-52.79853429987142,
-27.722008785135223
],
[
-50.72010819942622,
-27.722008785135223
],
[
-50.72010819942622,
-26.668723440791226
],
[
-52.79853429987142,
-26.668723440791226
]
]
],
"type": "Polygon"
}
}
]
},
"report": "Y"
}
A entrada do método é uma área especificada/selecionada e um valor valor lógico indicando se irá ou não ter relatório gerado.
Após executar a sexta pergunta da aplicação consumidora, uma resposta visual semelhante a imagem a seguir será mostrada.


Configurando o Arquivo questions.json
O arquivo questions.json, localizado na raiz do projeto, descreve as configurações básicas do consumidor. Quando o consumidor entra em execução esse arquivo é enviado para o Gateway que cadastra o consumidor na plataforma GeoProcess. Este arquivo definirá os projetos e temas aos quais este consumidor está vinculado, as perguntas que ele pode responder e os parâmetros necessários para essas perguntas. As configurações deste arquivo são mostradas a seguir.
Arquivo: questions.json
{
"projects": [
{
"consumer_project_id": "PGSTCS1",
"version": "1.0.0",
"title": "Projeto PGST Consumer Sample",
"role_tag": "PGSTCS"
}
],
"themes": [
{
"consumer_theme_id": "TPGSTCS1",
"version": "1.0.0",
"title": "Tema Único",
"role_tag": "TPGSTCS1",
"consumer_project_id": "PGSTCS1"
}
],
"questions": [
{
"consumer_question_id": "Q1",
"version": "1.0.1",
"consumer_theme_id": "TPGSTCS1",
"title": "Geração de Gráficos",
"description": "Dashboard com gráficos gerados a partir de dados artificiais.",
"role_tag": "QPGSTCS1",
"consumer_sources": [
"Dados Artificiais"
],
"config_items": []
},
{
"consumer_question_id": "Q2",
"version": "1.0.0",
"consumer_theme_id": "TPGSTCS1",
"title": "Busca informações sobre estados e municípios",
"description": "Busca informações sobre estados e municípios e gera alguns gráficos e tabelas.",
"role_tag": "QPGSTCS2",
"consumer_sources": [
"Fonte CAR"
],
"config_items": [
{
"id": "qtd_uf_menores",
"label": "Quantidade de Estados Menores",
"type": "range",
"min": 1,
"max": 27,
"step": 1
},
{
"id": "qtd_uf_maiores",
"label": "Quantidade de Estados Maiores",
"type": "range",
"min": 1,
"max": 27,
"step": 1
},
{
"id": "qtd_mun_menores",
"label": "Quantidade de Municípios Menores",
"type": "range",
"min": 1,
"max": 100,
"step": 1
},
{
"id": "qtd_mun_maiores",
"label": "Quantidade de Municípios Maiores",
"type": "range",
"min": 1,
"max": 100,
"step": 1
}
]
},
{
"consumer_question_id": "Q3",
"version": "1.0.0",
"consumer_theme_id": "TPGSTCS1",
"title": "Áreas que intersectam com a área do imóvel",
"description": "Busca por um imóvel retornando as áreas das camadas area_de_quilombolas e/ou terras_indigenas que intersectam com a área do imóvel.",
"role_tag": "QPGSTCS3",
"consumer_sources": [
"Fonte INCRA"
],
"config_items": [
{
"id": "cod_imovel",
"label": "Código do Imóvel",
"type": "text",
"maxlength": "43",
"required": true,
"text": "Você deve digitar um código do imóvel."
}
]
},
{
"consumer_question_id": "Q4",
"version": "1.0.0",
"consumer_theme_id": "TPGSTCS1",
"title": "Áreas que intersectam com área selecionada",
"description": "Busca todas as áreas das camadas area_imovel, area_de_quilombolas e/ou terras_indigenas que intersectam com a área selecionada passada como parâmetro.",
"role_tag": "QPGSTCS4",
"consumer_sources": [
"Fonte FUNAI"
],
"config_items": [
{
"id": "map",
"label": "Região Selecionada",
"type": "polygon",
"minArea": 1,
"text": "Você deve selecionar uma área."
}
]
},
{
"consumer_question_id": "Q5",
"version": "1.0.0",
"consumer_theme_id": "TPGSTCS1",
"title": "Busca por cidade que intersectam com as camadas selecionadas",
"description": "Busca baseada em uma cidade retornando as camadas (assentamentos_brasil e terras_indigenas) que intersectam com essa cidade",
"role_tag": "QPGSTCS5",
"consumer_sources": [
"Fonte IBGE"
],
"config_items": [
{
"id": "cod_city",
"label": "Município",
"type": "city",
"required": true,
"text": "Escolha um município."
},
{
"id": "layer_assentamentos_brasil",
"label": "Assentamentos Brasil",
"type": "check",
"true": "Y",
"false": "N"
},
{
"id": "layer_terras_indigenas",
"label": "Terras Indígenas",
"type": "check",
"true": "Y",
"false": "N"
}
]
},
{
"consumer_question_id": "Q6",
"version": "1.0.0",
"consumer_theme_id": "TPGSTCS1",
"title": "Geração de Relatório",
"description": "Dashboard com informações de dados artificiais e geração de relatório.",
"role_tag": "QPGSTCS6",
"consumer_sources": [
"Fonte IBGE"
],
"config_items": [
{
"id": "map",
"label": "Região Selecionada",
"type": "polygon",
"minArea": 1,
"text": "Você deve selecionar uma área."
},
{
"id": "report",
"label": "Gerar relatório",
"type": "check",
"true": "Y",
"false": "N"
}
]
}
]
}
Inicialmente, devemos definir uma lista de projetos no qual o consumidor está vinculado. No exemplo acima, o nosso consumidor está vinculado a um único projeto. Analise a configuração do projeto:
"projects": [
{
"consumer_project_id": "PGSTCS1",
"version": "1.0.0",
"title": "Projeto GeoProcess Consumer Sample",
"role_tag": "PGSTCS"
}
]
Em seguida, devemos definir a qual tema está relacionado um determinado projeto. Um tema é apenas um grupo para organização das perguntas dos projetos. Analise a configuração do tema:
"themes": [
{
"consumer_theme_id": "TPGSTCS1",
"version": "1.0.0",
"title": "Tema Único",
"role_tag": "TPGSTCS1",
"consumer_project_id": "PGSTCS1"
}
]
Por fim, devemos definir as perguntas que nosso consumidor é capaz de responder. Essa é a parte mais importante deste arquivo de configuração. Analise a configuração da pergunta:
"questions": [
{
"consumer_question_id": "Q1",
"version": "1.0.1",
"consumer_theme_id": "TPGSTCS1",
"title": "Geração de Gráficos",
"description": "Dashboard com gráficos gerados a partir de dados artificiais.",
"role_tag": "QPGSTCS1",
"consumer_sources": [
"Fonte IBGE"
],
"config_items": [
]
},
...
{
"consumer_question_id": "Q6",
"version": "1.0.0",
"consumer_theme_id": "TPGSTCS1",
"title": "Geração de Relatório",
"description": "Dashboard com informações de dados artificiais e geração de relatório.",
"role_tag": "QPGSTCS6",
"consumer_sources": [
"Fonte CAR"
],
"config_items": [
{
"id": "map",
"label": "Região Selecionada",
"type": "polygon",
"minArea": 1,
"text": "Você deve selecionar uma área."
},
{
"id": "report",
"label": "Gerar relatório",
"type": "check",
"true": "Y",
"false": "N"
}
]
}
]
O atributo config_items contém uma lista com os parâmetros de entrada necessários para responder uma determinada pergunta. Para cada parâmetro da pergunta iremos ter um conjunto de atributos possíveis.
Arquivo de Configuração .conf
Agora, vamos dar uma olhada no arquivo de configuração env.conf. Esse arquivo foi copiado do arquivo env_sample.conf e feito algumas alterações para funcionamento local de acordo com as configurações do nosso banco de dados. A seguir é mostrado esse arquivo seguido de uma breve explicação.
CONSUMER_CODE=sample
LOG_LEVEL=INFO
MODE=RUN
PORTAL_DIR=pgst-portal
#OPTIONAL
DB_NAME=pgst
DB_USER=postgres
DB_PASSWORD=root
DB_HOST=127.0.0.1
DB_PORT=5432
WMS_SERVER=http://localhost:8080
WMS_USER=ws1
WMS_PASSWORD=ws1
Os primeiros quatro atributos são obrigatórios. O atributo CONSUMER_CODE informa o nome do código consumidor. O atributo LOG_LEVEL informa o nível de detalhes impressos no sistema de log. Os valores possíveis são: DEBUG, INFO, WARNING, ERROR e CRITICAL.
Os oito próximos atributos são opcionais. Os atributos DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, DB_PORT são utilizados para estabelecer a conexão com o banco de dados do postgres, caso a aplicação integre com esse banco de dados. Os atributos WMS_SERVER, WMS_USER, WMS_PASSWORD são utilizados ao integrar a aplicação com o GeoServer.
Módulos para Testes
Na raiz do projeto existe uma pasta chamada tests que contém os testes de software implementados. Existem três tipos de testes de software disponíveis que são:
- Testes Unitários (unit): são os testes unitários definidos para testar métodos e partes isoladas do sistema.
- Testes de Contrato - contract: são os testes de contrato definidos para testar a interação do sistema com o envio de mensagens e suas respostas.
- Testes de Integração - integration: são os testes de integração definidos para testar a integração do sistema como um todo.
A seguir será melhor detalhado os testes de contrato que foram amplamente utilizados nesse exemplo.
Testes de Contrato:
Os testes de contrato são definidos na pasta tests/contract. Dentro dessa pasta terá uma subpasta para cada um dos testes a serem executados. Vamos ter uma subpasta para cada pergunta a ser avaliada (testada). Nesse exemplo, temos a subpasta 001 até 006 (totalizando seis perguntas). Dentro dessas pastas teremos um arquivo chamado test_00X.py que define os testes de contrato desse consumidor.
Quando esses testes são executados o arquivo answerRequest.json na mesma pasta é lido. Analise o arquivo mostrado abaixo.
Arquivo: answerRequest.json
{
"header": {
"type": "answer_request",
"status": "OK",
"next_consumer": null
},
"content": {
"user_info": {
"user": "dev",
"name": "Developer",
"email": "dev@ufla.br",
"ip": "127.0.0.1"
},
"consumer_question_id": "Q2",
"answer_request_id": 12,
"data": {
"qtd_uf_menores": 5,
"qtd_uf_maiores": 5,
"qtd_mun_menores": 50,
"qtd_mun_maiores": 50
}
}
}
Esse arquivo é relativo ao exemplo da segunda pergunta (pasta 002). A parte mais importante desse arquivo é a parte de dados (atributo data). Nesse exemplo, temos como entradas quatro números inteiros que serão armazenados nas variáveis qtd_uf_menores, qtd_uf_maiores, qtd_mun_menores e qtd_mun_maiores.
O arquivo answerRequest.json descreve as informações de entrada o consumidor. Ele é necessário apenas para executar o teste de contrato, quando o software vai para a produção esse arquivo não será utilizado e as entradas de dados serão definidas diretamente no Portal. Para executar esse teste de software analise a seção Executando a Aplicação.
Definindo Áreas de Interesse (GeoJson)
A ferramenta disponível no site geojson.io pode ser utilizada para desenhar um mapa e colocar as informações no arquivo answerRequest.json. Esse arquivo é utilizado para entrada de informações nas perguntas durante o teste de contrato. Esse site é útil apenas quando existirem perguntas que necessitam que áreas ou regiões selecionadas pelo usuário.
Para desenhar, clique em Draw Polygon (p), em seguida, clique sobre o mapa nas coordenadas que desejar fazer o desenho. Após fechar o desenho, cópie todo o código gerado em formato JSON exibido no lado direito. Analise a imagem abaixo.

Nesse exemplo, o código copiado tem o seguinte formato (aparência).
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
[-52.79853429987142, -26.668723440791226],
[-52.79853429987142, -27.722008785135223],
[-50.72010819942622, -27.722008785135223],
[-50.72010819942622, -26.668723440791226],
[-52.79853429987142, -26.668723440791226]
]
],
"type": "Polygon"
}
}
]
}
Esse código deve ser colado dentro do arquivo chamado answerRequest.json na pasta tests/contract/00X/.
{
"header": {
"type": "answer_request",
"status": "OK",
"next_consumer": null
},
"content": {
"user_info": {
"user": "dev",
"name": "Developer",
"email": "dev@ufla.br",
"ip": "127.0.0.1"
},
"consumer_question_id": "Q4",
"answer_request_id": 14,
"data": {
"map": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
[-52.79853429987142, -26.668723440791226],
[-52.79853429987142, -27.722008785135223],
[-50.72010819942622, -27.722008785135223],
[-50.72010819942622, -26.668723440791226],
[-52.79853429987142, -26.668723440791226]
]
],
"type": "Polygon"
}
}
]
}
}
}
}
Atenção
Quando o sistema estiver em produção, isso não será necessário, uma vez que, a infraestrutura do Portal fornece ferramentas para desenhar a área desejada. Quando estamos na etapa de desenvolvimento a utilização desse site é de grande ajuda.
Instalação
Pré-Requisitos
Instalações: São necessárias as seguintes instalações.
- Python
- Pip
- Git
- Postgres
- Postgis
- Docker Desktop
Projetos: São necessários os seguintes projetos.
- pgst-portal
- pgst-lib
Clonando a Aplicação
Primeiramente, clone o projeto pgst-consumer-sample utilizando o comando:
Observação
Esse projeto deve ser clonado dentro de uma pasta geoprocess, conforme a organização do projeto.
Configurando o BD
Para configuração do Banco de Dados. Foi executado o passo Criando um BD no pgAdmin na página Instalações. O banco criado foi chamado de pgst-sample. Em seguida, foi executado o passo Definindo Suporte para a Extensão do PostGIS no pgAdmin neste mesmo link para esse banco criado. O banco pgst-sample foi alimentado com quatro camadas ou tabelas que são: br_municipios_2022, br_uf_2022, area_de_quilombolas, assentamentos_brasil, terras_indigenas, area_imovel (apenas dados de Santa Catarina). Após subir as tabelas foi feita a alteração do SRID de cada uma das tabelas com o comando UpdateGeometrySRID.
Um dump do BD foi gerado e pode ser baixo aqui dump-bd-pgst-sample. Restaure este banco de dados em seu computador para executar todas as perguntas deste exemplo.
Configurando a Aplicação
Em seguida, copie o arquivo de configuração do ambiente utilizando o comando:
Em seguida, abra o arquivo env.conf e faça as atualizações necessárias conforme a configuração do seu ambiente de trabalho.
Instale o ambiente virtual venv para isolar as dependências do Python. Utilize o comando abaixo:
Ative o ambiente virtual em seu computador utilizando o comando abaixo:
Instale as dependências do projeto utilizando o comando abaixo:
Instale as dependências do projeto pgst-lib dentro do projeto consumidor.
Executando a Aplicação
Para executar a aplicação em modo de teste unitário, utilize a linha de comando abaixo:
Para executar a aplicação em modo teste de contrato, utilize a linha de comando abaixo:
Usando esse modo a resposta pode ser acessada depois do teste no arquivo answer.json na pasta answer.
Abra a aplicação através da URL http://127.0.0.1:8000/.
Informação
Para encerrar a execução do consumidor, basta apertar o botão x ou pressionar Ctrl + C.
Github do Projeto
A seguir temos o link para o github do projeto.