Skip to content
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

Feat/include both maxage and s maxage headers #60

Merged
merged 3 commits into from
Jul 23, 2024

Conversation

mnbf9rca
Copy link
Owner

@mnbf9rca mnbf9rca commented Jul 23, 2024

closes #50

Summary by Sourcery

This pull request adds support for handling both 'max-age' and 's-maxage' headers in cache control, introduces a new 'shared_expires' attribute to various models, and updates the test suite to cover these changes.

  • New Features:
    • Added support for parsing and handling both 'max-age' and 's-maxage' headers in cache control.
    • Introduced 'shared_expires' attribute to various models to store shared cache expiration times.
  • Enhancements:
    • Refactored cache control header parsing to handle both 'max-age' and 's-maxage' values.
    • Updated test cases to cover scenarios involving both 'max-age' and 's-maxage' headers.
  • Tests:
    • Extended test cases to validate the new 'shared_expires' attribute in models.
    • Added new test cases for various combinations of 'max-age' and 's-maxage' headers in cache control.

Copy link

sourcery-ai bot commented Jul 23, 2024

Reviewer's Guide by Sourcery

This pull request implements the inclusion of both 'max-age' and 's-maxage' headers in the cache control logic. The changes involve updating the client methods to handle both headers, modifying the test cases to validate the new logic, and updating the models to include a new 'shared_expires' field.

File-Level Changes

Files Changes
pydantic_tfl_api/models/disruption.py
pydantic_tfl_api/models/line.py
pydantic_tfl_api/models/mode.py
pydantic_tfl_api/models/prediction.py
pydantic_tfl_api/models/route_sequence.py
pydantic_tfl_api/models/stop_point.py
pydantic_tfl_api/models/stop_points_response.py
Added 'shared_expires' field to all relevant models.

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link

@sourcery-ai sourcery-ai bot left a 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: 1 issue found
  • 🟢 Security: all looks good
  • 🟡 Testing: 4 issues found
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

pydantic_tfl_api/client.py Outdated Show resolved Hide resolved
None,
None,
),
# Edge case: zero timedelta
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider adding a test case for very large timedelta values

It would be beneficial to add a test case for very large timedelta values to ensure the function handles them correctly without overflow or performance issues.

datetime(2023, 11, 15, 12, 45, 26),
datetime(2023, 11, 15, 12, 45, 26),
),
# Negative timedelta
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add a test case for non-integer timedelta values

Consider adding a test case where the timedelta value is a non-integer (e.g., a float or a string) to ensure the function handles such inputs gracefully.

"public, s-maxage=86400",
(86400, None),
),
# Both max-age and s-maxage zero
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider adding a test case for mixed valid and invalid directives

It would be useful to add a test case where one directive is valid and the other is invalid (e.g., max-age is a valid number, but s-maxage is malformed) to ensure the function handles such mixed scenarios correctly.

Suggested change
# Both max-age and s-maxage zero
# Both max-age and s-maxage zero
(
"public, max-age=0, s-maxage=0",
(0, 0),
),
# Mixed valid and invalid directives
(
"public, max-age=3600, s-maxage=invalid",
(3600, None),
),

],
)
def test_parse_timedelta(value, base_time, expected_result):
# Act
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider adding assertions for exception handling

In the test cases where exceptions are expected (e.g., invalid input), consider adding assertions to check the exception message to ensure it is informative and accurate.

Suggested change
# Act
# Act & Assert
if isinstance(expected_result, type) and issubclass(expected_result, Exception):
with pytest.raises(expected_result) as exc_info:
Client._parse_timedelta(value, base_time)
assert str(exc_info.value) == str(expected_result())
else:
result = Client._parse_timedelta(value, base_time)
assert result == expected_result

Comment on lines 122 to +134
if expected_name is None:
with pytest.raises(ValidationError):
Client._create_model_with_expiry(None, Model, response_json, result_expiry)
Client._create_model_with_expiry(None, Model, response_json, result_expiry, shared_expiry)
else:
instance = Client._create_model_with_expiry(
None, Model, response_json, result_expiry
None, Model, response_json, result_expiry, shared_expiry
)

# Assert
assert instance.name == expected_name
assert instance.age == expected_age
assert instance.content_expires == expected_expiry
assert instance.shared_expires == expected_shared_expiry
Copy link

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)

ExplanationAvoid 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

Comment on lines +296 to +299
if cache_control_header is not None:
response.headers = {"cache-control": cache_control_header}
else:
response.headers = {}
Copy link

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)

ExplanationAvoid 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

Comment on lines 583 to +589
if isinstance(response_json, dict):
mock_create_model_with_expiry.assert_called_with(
Model, response_json, result_expiry
Model, response_json, result_expiry, shared_expiry
)
else:
for item in response_json:
mock_create_model_with_expiry.assert_any_call(Model, item, result_expiry)
mock_create_model_with_expiry.assert_any_call(Model, item, result_expiry, shared_expiry)
Copy link

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)

ExplanationAvoid 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

Comment on lines 588 to +589
for item in response_json:
mock_create_model_with_expiry.assert_any_call(Model, item, result_expiry)
mock_create_model_with_expiry.assert_any_call(Model, item, result_expiry, shared_expiry)
Copy link

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)

ExplanationAvoid 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

Comment on lines +102 to 104
result = self._create_model_instance(Model, data, result_expiry, shared_expiry)

return result
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
result = self._create_model_instance(Model, data, result_expiry, shared_expiry)
return result
return self._create_model_instance(Model, data, result_expiry, shared_expiry)

Using 'Optional[datetime]' instead of 'datetime | None' would be more consistent with the rest of the codebase.

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@mnbf9rca mnbf9rca merged commit 6c5a4ee into main Jul 23, 2024
6 checks passed
@mnbf9rca mnbf9rca deleted the feat/include-both-maxage-and-s-maxage-headers branch July 23, 2024 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add maxage and map to result_expiry and rename s-maxage as shared_result_expiry
1 participant