-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chore/add tests #46
Chore/add tests #46
Conversation
Reviewer's Guide by SourceryThis pull request primarily focuses on adding tests for the File-Level Changes
Tips
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @mnbf9rca - I've reviewed your changes and they look great!
Here's what I looked at during the review
- 🟡 General issues: 4 issues found
- 🟢 Security: all looks good
- 🟡 Testing: 1 issue found
- 🟢 Complexity: all looks good
- 🟢 Documentation: all looks good
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.
|
||
def _get_result_expiry(self, response: Response) -> datetime | None: | ||
s_maxage = self._get_s_maxage_from_cache_control_header(response) | ||
request_datetime = parsedate_to_datetime(response.headers.get("date")) | ||
request_datetime = parsedate_to_datetime(response.headers.get("date")) if "date" in response.headers else None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Handling of missing 'date' header
Returning None
when the 'date' header is missing might lead to issues downstream if request_datetime
is expected to be a datetime object. Consider raising an exception or handling this case more explicitly.
@@ -90,7 +90,7 @@ def _get_model(self, model_name: str) -> BaseModel: | |||
|
|||
def _create_model_instance( | |||
self, Model: BaseModel, response_json: Any, result_expiry: datetime | None | |||
): | |||
) -> BaseModel | List[BaseModel]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Return type annotation
The return type annotation BaseModel | List[BaseModel]
might be too broad. If possible, consider specifying more precise types to improve type safety and readability.
) -> BaseModel | List[BaseModel]: | |
) -> Union[Model, List[Model]]: |
return self._send_request_and_deserialize( | ||
endpoints["stopPointsByLineId"].format(line_id), "StopPoint" | ||
) | ||
if response.status_code != 200: | ||
return self._deserialize_error(response) | ||
return self._deserialize("StopPoint", response) | ||
|
||
def get_line_meta_modes(self) -> models.Mode | models.ApiError: | ||
response = self.client.send_request(endpoints["lineMetaModes"]) | ||
if response.status_code != 200: | ||
return self._deserialize_error(response) | ||
return self._deserialize("Mode", response) | ||
return self._send_request_and_deserialize(endpoints["lineMetaModes"], "Mode") | ||
|
||
def get_lines( | ||
self, line_id: str | None = None, mode: str | None = None | ||
) -> models.Line | List[models.Line] | models.ApiError: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Refactoring to use _send_request_and_deserialize
The refactoring to use _send_request_and_deserialize
improves code reuse and readability. However, ensure that the new method handles all edge cases and error conditions that were previously managed in the individual methods.
@@ -11,6 +12,7 @@ class ApiError(BaseModel): | |||
|
|||
@field_validator('timestamp_utc', mode='before') | |||
def parse_timestamp(cls, v): | |||
return datetime.strptime(v, '%a, %d %b %Y %H:%M:%S %Z') | |||
return v if isinstance(v, datetime) else parsedate_to_datetime(v) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Field validator logic
The field validator now handles both datetime objects and string dates. Ensure that parsedate_to_datetime
correctly handles all expected date formats and edge cases.
return v if isinstance(v, datetime) else parsedate_to_datetime(v) | |
if isinstance(v, datetime): | |
return v | |
try: | |
return parsedate_to_datetime(v) | |
except (TypeError, ValueError): | |
raise ValueError(f"Invalid date format: {v}") |
@pytest.mark.parametrize( | ||
"Model, response_json, result_expiry, expected_name, expected_age, expected_expiry", | ||
[ | ||
# Happy path tests | ||
( | ||
PydanticTestModel, | ||
{"name": "Alice", "age": 30}, | ||
datetime(2023, 12, 31), | ||
"Alice", | ||
30, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (testing): Missing test for invalid model name in test_create_model_with_expiry
Consider adding a test case for an invalid model name to ensure that the function handles it gracefully.
if expected_name is None: | ||
with pytest.raises(ValidationError): | ||
Client._create_model_with_expiry(None, Model, response_json, result_expiry) | ||
else: | ||
instance = Client._create_model_with_expiry( | ||
None, Model, response_json, result_expiry | ||
) | ||
|
||
# Assert | ||
assert instance.name == expected_name | ||
assert instance.age == expected_age | ||
assert instance.content_expires == expected_expiry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Avoid conditionals in tests. (no-conditionals-in-tests
)
Explanation
Avoid complex code, like conditionals, in test functions.Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
- loops
- conditionals
Some ways to fix this:
- Use parametrized tests to get rid of the loop.
- Move the complex logic into helpers.
- Move the complex part into pytest fixtures.
Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.
Software Engineering at Google / Don't Put Logic in Tests
if exception: | ||
with pytest.raises(exception): | ||
Client._get_model(client, model_name) | ||
else: | ||
result = Client._get_model(client, model_name) | ||
assert result == expected_result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Avoid conditionals in tests. (no-conditionals-in-tests
)
Explanation
Avoid complex code, like conditionals, in test functions.Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
- loops
- conditionals
Some ways to fix this:
- Use parametrized tests to get rid of the loop.
- Move the complex logic into helpers.
- Move the complex part into pytest fixtures.
Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.
Software Engineering at Google / Don't Put Logic in Tests
if isinstance(response_json, dict): | ||
mock_create_model_with_expiry.assert_called_with( | ||
Model, response_json, result_expiry | ||
) | ||
else: | ||
for item in response_json: | ||
mock_create_model_with_expiry.assert_any_call(Model, item, result_expiry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Avoid conditionals in tests. (no-conditionals-in-tests
)
Explanation
Avoid complex code, like conditionals, in test functions.Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
- loops
- conditionals
Some ways to fix this:
- Use parametrized tests to get rid of the loop.
- Move the complex logic into helpers.
- Move the complex part into pytest fixtures.
Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.
Software Engineering at Google / Don't Put Logic in Tests
for item in response_json: | ||
mock_create_model_with_expiry.assert_any_call(Model, item, result_expiry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Avoid loops in tests. (no-loop-in-tests
)
Explanation
Avoid complex code, like loops, in test functions.Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:
- loops
- conditionals
Some ways to fix this:
- Use parametrized tests to get rid of the loop.
- Move the complex logic into helpers.
- Move the complex part into pytest fixtures.
Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.
Software Engineering at Google / Don't Put Logic in Tests
Summary by Sourcery
This pull request refactors the Client class to improve request handling and deserialization, updates the ApiError model for better timestamp parsing, and adds comprehensive tests for various functionalities of the Client class.