Esse projeto contém uma série de informações sobre o que eu aprendi aqui na Trybe ao longo do curso de desenvolvimento web da Trybe.
Neste projeto foram implementadas análises a partir de um conjunto de dados sobre empregos. As implementações foram incorporadas a um aplicativo Web desenvolvido com Flask (um framework web muito popular na comunidade Python). Também tem testes para a implementação de uma análise de dados.
🚵 Habilidades trabalhadas:
- Utilizar o terminal interativo do Python.
- Utilizar estruturas condicionais e de repetição.
- Utilizar funções built-in do Python.
- Utilizar tratamento de exceções.
- Realizar a manipulação de arquivos.
- Escrever funções.
- Escrever testes com Pytest.
- Escrever seus próprios módulos e importá-los em outros códigos.
Esse projeto foi proposto pelo curso de desenvolvimento web da Trybe.
Esse projeto foi desenvolvido no bloco de ciências da computação. Foi meu primeiro projeto em Python.
Os commits foram feitos de acordo com os requisitos finalizados.
Todo o projeto foi feita na branch juliana-oliveira-project-job-insigths.
python3 -m venv .venv && source .venv/bin/activate
python3 -m pip install -r dev-requirements.txt
Este repositório já contém um template com a estrutura de diretórios e arquivos, tanto de código quanto de teste criados. Veja abaixo:
Na estrutura deste template, você deve implementar as funções necessárias. Novos arquivos e funções podem ser criados conforme a necessidade da sua implementação, porém não remova arquivos já existentes.
Para executar os testes certifique-se de que você está com o ambiente virtual ativado.
Executar os testes
$ python3 -m pytest
O arquivo pyproject.toml
já configura corretamente o pytest. Entretanto, caso você tenha problemas com isso e queira explicitamente uma saída completa, o comando é:
python3 -m pytest -s -vv
Caso precise executar apenas um arquivo de testes basta executar o comando:
python3 -m pytest tests/nomedoarquivo.py
Caso precise executar apenas uma função de testes basta executar o comando:
python3 -m pytest -k nome_da_func_de_tests
Se desejar que os testes parem de ser executados quando acontecer o primeiro erro, use o parâmetro -x
python3 -m pytest -x tests/test_jobs.py
Para executar um teste específico de um arquivo, basta executar o comando:
python3 -m pytest tests/nomedoarquivo.py::test_nome_do_teste
Esse foi um projeto individual.
Foi usado Visual Studio Code, além do Trello que auxiliou na organização das tarefas.
No trabalho do desenvolvimento de software a gente sempre tem prazos, muitas vezes os prazos são apertados.
Por outro lado, eu não quero criar algo que não entendo perfeitamente, como também fazer códigos rápidos pode levar a erros que podem demorar muito pra corrigir.
Por isso, usei e sempre uso o método Baby Steps, que é uma estratégia de abordar o desafio passo à passo, defensivamente.
Baby steps é um termo em inglês que quer dizer passos de bebê. Refere-se a fazer as coisas, quaisquer que sejam, devagar, com calma, passo a passo.
Implemente em: src/jobs.py
Para começarmos a processar os dados, devemos antes carregá-los em nossa aplicação. Esta função será responsável por abrir o arquivo CSV e retornar os dados no formato de uma lista de dicionários.
- A função deve receber um path (uma string com o caminho para um arquivo).
- A função deve abrir o arquivo e ler seus conteúdos.
- A função deve tratar o arquivo como CSV.
- A função deve retornar uma lista de dicionários, onde as chaves são os cabeçalhos de cada coluna e os valores correspondem a cada linha.
📝Exemplo
Se o conteúdo do arquivo for:nome,cidade,telefone
Ana,Curitiba,1111111
Bernardo,Santos,999999
O retorno da função deverá ser:
[
{"nome": "Ana", "cidade": "Curitiba", "telefone": "1111111"},
{"nome": "Bernardo", "cidade": "Santos", "telefone": "999999"}
]
✍️ Teste manual
Abra um terminal Python importando estas funções através do comandopython3 -i src/jobs.py
e invoque a função utilizando diferentes _paths_.
🤖 O que será verificado pelo avaliador
- A função abre o arquivo passado como parâmetro
- A função retorna uma lista de dicionários
- A função retorna a quantidade correta de itens na lista
- Nos dicionários retornados pela função, as chaves correspondem aos cabeçalhos do arquivo
Implemente em:
src/insights.py
Agora que temos como carregar os dados, podemos começar a extrair informação deles. Primeiro, vamos identificar quais tipos de empregos existem.
- A função deve receber o path do arquivo csv com os dados.
- A função deve invocar a função
jobs.read
com o path recebido para obter os dados. - A função deve retornar uma lista de valores únicos presentes na coluna
job_type
.
🤖 O que será verificado pelo avaliador
- A função carrega os dados do arquivo recebido como parâmetro
- A função retorna a quantidade correta de valores
- A função retorna os valores corretos
- A função desconsidera valores vazios
Implemente em:
src/insights.py
Da mesma forma, agora iremos identificar quais indústrias estão representadas nesse conjunto de dados.
- A função deve obter os dados da mesma forma que o requisito 2.
- A função deve retornar uma lista de valores únicos presentes na coluna
industry
. - A função desconsidera valores vazios
🤖 O que será verificado pelo avaliador
- A função carrega os dados do arquivo recebido como parâmetro
- A função retorna a quantidade correta de valores
- A função retorna os valores corretos
Implemente em:
src/insights.py
Os dados apresentam faixas salariais para cada emprego exibido. Vamos agora encontrar o maior valor de todas as faixas.
- A função deve obter os dados da mesma forma que o requisito 2.
- A função deve ignorar os valores ausentes.
- A função deve retornar um valor inteiro com o maior salário presente na coluna
max_salary
.
🤖 O que será verificado pelo avaliador
- A função carrega os dados do arquivo recebido como parâmetro
- A função retorna o valor correto
Implemente em:
src/insights.py
Os dados apresentam faixas salariais para cada emprego exibido. Vamos agora encontrar o menor valor de todas as faixas.
- A função deve obter os dados da mesma forma que o requisito 2.
- A função deve ignorar os valores ausentes.
- A função deve retornar um valor inteiro com o menor salário presente na coluna
min_salary
.
🤖 O que será verificado pelo avaliador
- A função carrega os dados do arquivo recebido como parâmetro
- A função retorna o valor correto
Implemente em:
src/insights.py
Os empregos estão listados em um aplicativo web. Para permitir que a pessoa usuária possa filtrar os empregos por tipo de emprego, vamos precisar implementar esse filtro.
- A função deve receber uma lista de dicionários
jobs
como primeiro parâmetro. - A função deve receber uma string
job_type
como segundo parâmetro. - A função deve retornar uma lista com todos os empregos onde a coluna
job_type
corresponde ao parâmetrojob_type
.
🤖 O que será verificado pelo avaliador
- A função retorna a quantidade correta de valores
- A função retorna os valores corretos
- A função retorna os valores na ordem correta
- A função retorna uma lista vazia para
job_types
ausentes nosjobs
recebidos
Implemente em:
src/insights.py
Do mesmo modo, o aplicativo precisa permitir uma filtragem por indústria. Vamos precisar implementar esse filtro também.
- A função deve receber uma lista de dicionários
jobs
como primeiro parâmetro. - A função deve receber uma string
industry
como segundo parâmetro. - A função deve retornar uma lista de dicionários com todos os empregos onde a coluna
industry
corresponde ao parâmetroindustry
.
🤖 O que será verificado pelo avaliador
- A função retorna a quantidade correta de valores
- A função retorna os valores corretos
- A função retorna os valores na ordem correta
- A função retorna uma lista vazia para
job_types
ausentes nosjobs
recebidos
Implemente em:
src/insights.py
O aplicativo vai precisar filtrar os empregos por salário também. Como uma função auxiliar, implemente matches_salary_range
para conferir que o salário procurado está dentro da faixa salarial daquele emprego. Vamos aproveitar também para conferir se a faixa salarial faz sentido -- isto é, se o valor mínimo é menor que o valor máximo.
- A função deve receber um dicionário
job
como primeiro parâmetro, com as chavesmin_salary
emax_salary
. - A função deve receber um inteiro
salary
como segundo parâmetro. - A função deve lançar um erro
ValueError
nos seguintes casos:- alguma das chaves
min_salary
oumax_salary
estão ausentes no dicionário; - alguma das chaves
min_salary
oumax_salary
tem valores não-numéricos; - o valor de
min_salary
é maior que o valor demax_salary
; - o parâmetro
salary
tem valores não numéricos;
- alguma das chaves
- A função deve retornar
True
se o salário procurado estiver dentro da faixa salarial ouFalse
se não estiver.
🤖 O que será verificado pelo avaliador
- A função retorna o booleano correto
- A função lança um
ValueError
se o valor demin_salary
for maior que o valor demax_salary
- A função lança um
ValueError
se as chavesmin_salary
oumax_salary
tiverem valores não numéricos - A função lança um
ValueError
se o parâmetrosalary
tiver valor não numérico - A função lança um
ValueError
se as chavesmin_salary
oumax_salary
estiverem ausentes no dicionário
Implemente em:
src/insights.py
Agora vamos implementar o filtro propriamente dito. Para esta filtragem, podemos usar a função auxiliar implementada no requisito anterior -- tomando o cuidado de descartar os empregos que apresentarem faixas salariais inválidas.
- A função deve receber uma lista de dicionários
jobs
como primeiro parâmetro. - A função deve receber um inteiro
salary
como segundo parâmetro. - A função deve ignorar os empregos com valores inválidos para
min_salary
oumax_salary
. - A função deve retornar uma lista com todos os empregos onde o salário
salary
estiver entre os valores da colunamin_salary
emax_salary
.
🤖 O que será verificado pelo avaliador
- A função retorna a quantidade correta de valores
- A função retorna os valores corretos
- A função retorna os valores na ordem correta
- Empregos onde as chaves
min_salary
oumax_salary
tiverem valores não numéricos devem ser ignorados - Empregos onde o valor de
min_salary
for maior que o valor demax_salary
devem ser ignorados
Implemente em:
tests/counter/test_counter.py
A empresa cliente contratou um relatório que informa a quantidade de ocorrências das palavra Python e Javascript nos dados e, para isso, temos uma implementação pronta em src/counter.py
. Durante o desenvolvimento, sofremos com alguns bugs
, que já foram resolvidos. Para termos certeza e confiança da nossa entrega, no entanto, e não corrermos riscos, precisaremos de testes automatizados que garantam isso!
O nome deste teste deve ser test_counter
, e ele deve garantir que atenda estas especificações:
- Chamar a função
count_ocurrences
passando dois parâmetros:path
uma string com o caminho do arquivo (src/jobs.csv
);word
uma string com a palavra a ser contabilizada.
- Garantir que a função retorna corretamente a quantidade de ocorrências da palavra solicitada
- A contagem de palavras deve ser case insentitive, ou seja, não diferenciar letras maiúsculas de minúsculas
📌Como seu teste é avaliado
O teste da Trybe irá avaliar se o seu teste está passando conforme seu objetivo e confirmará se ele está falhando em alguns casos que deve falhar. Para estes testes que esperemos que falhe, o requisito será considerado atendido quando a resposta do Pytest forXFAIL(Expected Fail)
ao invés de PASS
ou FAIL
.
🤖 O que será verificado pelo avaliador
- O teste rejeita implementações que não retornam a quantidade de palavras corretamente.
- O teste aprova implementações corretas.
- Se o teste não é um falso positivo, ou seja, teste que passa sem realmente testar o código.
Implemente em:
tests/brazilian/test_brazilian_jobs.py
A empresa cliente analisa relatórios em inglês, porém agora ela quer expandir seus negócios aqui para o Brasil e deseja analisar relatórios em português também. No entanto, as chaves do dict
que usamos pra organizar os dados devem continuar em inglês. Ou seja: para gerar o relatório, deveremos ler as chaves em português e traduzi-las para inglês para povoar os nossos dados.
Nossa equipe já implementou essa função, a read_brazilian_file
, na qual adotamos a estratégia de chamar o método original read
, que implementamos no requisito 1
, e depois traduzimos as chaves para o inglês. Agora precisamos criar testes para ter certeza que esta tudo certo!
O nome deste teste deve ser test_brazilian_jobs
, e ele deve garantir que atenda as seguintes especificações:
- Chamar a função
read_brazilian_file
e ela deve receber um parâmetro:path
que é uma string com o caminho do arquivo csv em português (tests/mocks/brazilians_jobs.csv
);- Retorna uma lista de dicionários com as chaves em inglês
📝Exemplo
O dicionário:{"titulo": "Maquinista", "salario": "2000", "tipo": "trainee"}
Deve ser traduzido para: {"title": "Maquinista", "salary": "2000", "type": "trainee"}
📌Como seu teste é avaliado
O teste da Trybe irá avaliar se o seu teste está passando conforme seu objetivo e confirmará se ele está falhando em alguns casos que deve falhar. Para estes testes que esperemos que falhe, o requisito será considerado atendido quando a resposta do Pytest forXFAIL(Expected Fail)
ao invés de PASS
ou FAIL
.
🤖 O que será verificado pelo avaliador
- O teste rejeita implementações que não retornam as chaves traduzidas corretamente.
- O teste aprova implementações corretas.
- Se o teste não é um falso positivo, ou seja, teste que passa sem realmente testar o código.