From 76c04a46d58a4078b722fcfd2937cb8a34b5b75f Mon Sep 17 00:00:00 2001 From: Augusto Herrmann Date: Tue, 30 Jul 2024 15:54:35 -0300 Subject: [PATCH 1/6] Remove unused imports --- src/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schemas.py b/src/schemas.py index 7ec82db..1372f3a 100644 --- a/src/schemas.py +++ b/src/schemas.py @@ -6,7 +6,7 @@ """ from datetime import date, datetime -from typing import Any, Dict, List, Optional +from typing import List, Optional from pydantic import BaseModel, ConfigDict, Field, EmailStr from pydantic import model_validator, field_validator From 4a62018d4bd81183105fc4dbd7d3edb7a92341f3 Mon Sep 17 00:00:00 2001 From: Augusto Herrmann Date: Tue, 30 Jul 2024 16:37:33 -0300 Subject: [PATCH 2/6] Remove unused import --- src/schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schemas.py b/src/schemas.py index 1372f3a..b5499e1 100644 --- a/src/schemas.py +++ b/src/schemas.py @@ -5,7 +5,7 @@ Pydantic: https://docs.pydantic.dev/2.0/ """ -from datetime import date, datetime +from datetime import date from typing import List, Optional from pydantic import BaseModel, ConfigDict, Field, EmailStr From 913a3e8cf47caea960d6bbe01e47c23456e58d0d Mon Sep 17 00:00:00 2001 From: Augusto Herrmann Date: Tue, 30 Jul 2024 16:39:25 -0300 Subject: [PATCH 3/6] Handle time-aware datetimes --- src/schemas.py | 11 ++------ tests/participantes_test.py | 50 ++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/schemas.py b/src/schemas.py index b5499e1..4c923d3 100644 --- a/src/schemas.py +++ b/src/schemas.py @@ -9,6 +9,7 @@ from typing import List, Optional from pydantic import BaseModel, ConfigDict, Field, EmailStr +from pydantic import NonNegativeInt, PastDatetime, PositiveInt from pydantic import model_validator, field_validator from models import ( @@ -562,7 +563,7 @@ class ParticipanteSchema(BaseModel): title="Modalidade e regime de execução do trabalho", description=Participante.modalidade_execucao.comment, ) - data_assinatura_tcr: Optional[datetime] = Field( + data_assinatura_tcr: Optional[PastDatetime] = Field( title="Data de assinatura do TCR", description=Participante.data_assinatura_tcr.comment, ) @@ -606,14 +607,6 @@ def cpf_part_validate(cpf: str) -> str: "Valida o CPF do participante." return cpf_validate(cpf) - @field_validator("data_assinatura_tcr") - @staticmethod - def data_assinatura_tcr_validate(data_assinatura_tcr: datetime) -> datetime: - "Valida a data de assinatura do TCR." - if data_assinatura_tcr > datetime.now(): - raise ValueError("A data_assinatura_tcr não pode ser data futura.") - return data_assinatura_tcr - class Token(BaseModel): access_token: str diff --git a/tests/participantes_test.py b/tests/participantes_test.py index 190d2bb..7da013c 100644 --- a/tests/participantes_test.py +++ b/tests/participantes_test.py @@ -2,11 +2,11 @@ Testes relacionados aos status de participantes. """ -from datetime import date, datetime, timedelta - -from httpx import Client +from datetime import date, datetime, timedelta, timezone +from typing import Optional from fastapi import status +from httpx import Client import pytest @@ -532,10 +532,7 @@ def test_put_invalid_data_assinatura_tcr( ): """Tenta criar um participante com data futura do TCR.""" # data de amanhã - input_part["data_assinatura_tcr"] = ( - (date.today() + timedelta(days=1)) - .isoformat() - ) + input_part["data_assinatura_tcr"] = (date.today() + timedelta(days=1)).isoformat() response = client.put( f"/organizacao/SIAPE/{user1_credentials['cod_unidade_autorizadora']}" f"/{input_part['cod_unidade_lotacao']}" @@ -545,9 +542,44 @@ def test_put_invalid_data_assinatura_tcr( ) assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - detail_messages = "A data_assinatura_tcr não pode ser data futura." + detail_messages = "Input should be in the past" assert any( - f"Value error, {message}" in error["msg"] + message in error["msg"] for message in detail_messages for error in response.json().get("detail") ) + + +@pytest.mark.parametrize( + "timezone_utc", + [ + -3, # hora de Brasília + -5, # horário de Rio Branco + (None), # sem fuso horário (timezone-naïve) + ], +) +def test_put_data_assinatura_tcr_timezone( + truncate_participantes, # pylint: disable=unused-argument + input_part: dict, + user1_credentials: dict, + timezone_utc: Optional[int], + header_usr_1: dict, + client: Client, +): + """Tenta criar um participante com data futura do TCR.""" + # data de amanhã + input_part["data_assinatura_tcr"] = ( + datetime.now( + **({"tz": timezone(timedelta(hours=timezone_utc))} if timezone_utc else {}) + ) + - timedelta(days=1) + ).isoformat() + response = client.put( + f"/organizacao/SIAPE/{user1_credentials['cod_unidade_autorizadora']}" + f"/{input_part['cod_unidade_lotacao']}" + f"/participante/{input_part['matricula_siape']}", + json=input_part, + headers=header_usr_1, + ) + + assert response.status_code == status.HTTP_201_CREATED From 39dfb8708cd3a1409c45d644d1e985929540addc Mon Sep 17 00:00:00 2001 From: Augusto Herrmann Date: Tue, 30 Jul 2024 16:40:09 -0300 Subject: [PATCH 4/6] Use Pydantic's native types to simplify the code --- src/schemas.py | 25 ++++--------------------- tests/participantes_test.py | 7 ++----- tests/plano_entregas/core_test.py | 8 ++++---- 3 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/schemas.py b/src/schemas.py index 4c923d3..e2853b0 100644 --- a/src/schemas.py +++ b/src/schemas.py @@ -383,7 +383,7 @@ class EntregaSchema(BaseModel): description=Entrega.nome_entrega.comment, max_length=STR_FIELD_MAX_SIZE, ) - meta_entrega: int = Field( + meta_entrega: NonNegativeInt = Field( title="Meta estipulada na inclusão no plano", description=Entrega.meta_entrega.comment, ) @@ -406,13 +406,6 @@ class EntregaSchema(BaseModel): max_length=STR_FIELD_MAX_SIZE, ) - @field_validator("meta_entrega") - @staticmethod - def must_be_positive(meta_entrega: int) -> int: - if meta_entrega < 0: - raise ValueError("Valor meta_entrega deve ser maior ou igual a 0.") - return meta_entrega - @model_validator(mode="after") def validate_meta_percentual(self) -> "EntregaSchema": if ( @@ -435,15 +428,15 @@ class PlanoEntregasSchema(BaseModel): title="Código do sistema da unidade", description=PlanoEntregas.origem_unidade.comment, ) - cod_unidade_autorizadora: int = Field( + cod_unidade_autorizadora: PositiveInt = Field( title="Código da unidade autorizadora", description=PlanoEntregas.cod_unidade_autorizadora.comment, ) - cod_unidade_instituidora: int = Field( + cod_unidade_instituidora: PositiveInt = Field( title="Código da unidade instituidora", description=PlanoEntregas.cod_unidade_instituidora.comment, ) - cod_unidade_executora: int = Field( + cod_unidade_executora: PositiveInt = Field( title="Código da unidade executora", description=PlanoEntregas.cod_unidade_executora.comment, ) @@ -477,16 +470,6 @@ class PlanoEntregasSchema(BaseModel): description="Lista de entregas associadas ao Plano de Entregas", ) - @field_validator( - "cod_unidade_autorizadora", "cod_unidade_instituidora", "cod_unidade_executora" - ) - @staticmethod - def validate_codigo_unidade(value: int) -> int: - """Valida o código da unidade.""" - if value < 1: - raise ValueError(f"Código da unidade inválido: {value}") - return value - @model_validator(mode="after") def validate_entregas_uniqueness(self) -> "PlanoEntregasSchema": """Valida a unicidade das entregas.""" diff --git a/tests/participantes_test.py b/tests/participantes_test.py index 7da013c..6bb91c9 100644 --- a/tests/participantes_test.py +++ b/tests/participantes_test.py @@ -266,7 +266,7 @@ def test_put_participante_missing_mandatory_fields( ): """Tenta submeter participantes faltando campos obrigatórios""" matricula_siape = input_part["matricula_siape"] - cod_unidade_lotacao = input_part['cod_unidade_lotacao'] + cod_unidade_lotacao = input_part["cod_unidade_lotacao"] offset, field_list = missing_fields for field in field_list: del input_part[field] @@ -404,10 +404,7 @@ def test_put_participante_invalid_matricula_siape( ] received_error = response.json().get("detail") if isinstance(received_error, str): - assert any( - message in received_error - for message in detail_messages - ) + assert any(message in received_error for message in detail_messages) else: assert any( f"Value error, {message}" in error["msg"] diff --git a/tests/plano_entregas/core_test.py b/tests/plano_entregas/core_test.py index f86b5f5..17d73f1 100644 --- a/tests/plano_entregas/core_test.py +++ b/tests/plano_entregas/core_test.py @@ -587,9 +587,9 @@ def test_create_invalid_cod_unidade( assert response.status_code == http_status.HTTP_201_CREATED else: assert response.status_code == http_status.HTTP_422_UNPROCESSABLE_ENTITY - detail_message = "Código da unidade inválido" + detail_message = "Input should be greater than 0" assert any( - f"Value error, {detail_message}" in error["msg"] + detail_message in error["msg"] for error in response.json().get("detail") ) @@ -640,10 +640,10 @@ def test_create_entrega_invalid_percent( elif tipo_meta == "unidade" and (meta_entrega < 0): assert response.status_code == http_status.HTTP_422_UNPROCESSABLE_ENTITY detail_message = ( - "Valor meta_entrega deve ser maior ou igual a 0." + "Input should be greater than or equal to 0" ) assert any( - f"Value error, {detail_message}" in error["msg"] + detail_message in error["msg"] for error in response.json().get("detail") ) else: From 205d3e6c050ae4fb7932a8adb3cee571d9db20c3 Mon Sep 17 00:00:00 2001 From: Augusto Herrmann Date: Tue, 30 Jul 2024 16:43:56 -0300 Subject: [PATCH 5/6] Remove unnecessary parentheses --- tests/participantes_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/participantes_test.py b/tests/participantes_test.py index 6bb91c9..cbb9f1f 100644 --- a/tests/participantes_test.py +++ b/tests/participantes_test.py @@ -552,7 +552,7 @@ def test_put_invalid_data_assinatura_tcr( [ -3, # hora de Brasília -5, # horário de Rio Branco - (None), # sem fuso horário (timezone-naïve) + None, # sem fuso horário (timezone-naïve) ], ) def test_put_data_assinatura_tcr_timezone( From d3c614b2ed05bfbf754759ff3eb86a54a685c392 Mon Sep 17 00:00:00 2001 From: Augusto Herrmann Date: Tue, 30 Jul 2024 16:49:24 -0300 Subject: [PATCH 6/6] Fix docstring for test and comment --- tests/participantes_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/participantes_test.py b/tests/participantes_test.py index cbb9f1f..5afc094 100644 --- a/tests/participantes_test.py +++ b/tests/participantes_test.py @@ -563,8 +563,8 @@ def test_put_data_assinatura_tcr_timezone( header_usr_1: dict, client: Client, ): - """Tenta criar um participante com data futura do TCR.""" - # data de amanhã + """Tenta criar um participante com data de assinatura do TCR em + diversos fuso-horários.""" input_part["data_assinatura_tcr"] = ( datetime.now( **({"tz": timezone(timedelta(hours=timezone_utc))} if timezone_utc else {})