-
-
Notifications
You must be signed in to change notification settings - Fork 219
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
Sandbox: Enable mypy type checker #560
Conversation
Caution Review failedThe pull request is closed. WalkthroughThis pull request introduces several modifications across multiple files, primarily focusing on enhancing type annotations, error handling, and method signatures in the Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (2)
responder/routes.py (1)
Line range hint
1-359
: Consider enhancing type safety across the router implementation.While the current changes enable mypy and handle known type checking limitations, there are opportunities to enhance type safety:
- Add type annotations to method parameters and return types
- Consider using TypeVar for generic type parameters
- Use Protocol classes to define interface contracts for ASGI/WSGI apps
- Add type annotations to class variables and instance attributes
This would provide better type safety and improved IDE support.
responder/api.py (1)
228-233
: LGTM: Type ignore is consistent with usage pattern.The type ignore for the
status_code
parameter is consistent with the previous usage pattern. Consider updating the docstring to mention thatstatus_code
accepts HTTP status codes from thestatus_codes
module.Update the docstring parameter description:
- :param status_code: an `API.status_codes` attribute, or an integer, - representing the HTTP status code of the redirect. + :param status_code: An HTTP status code from `API.status_codes` module (e.g., + status_codes.HTTP_301) or an integer, representing the + HTTP status code of the redirect.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pyproject.toml
is excluded by!**/*.toml
📒 Files selected for processing (5)
- responder/api.py (2 hunks)
- responder/ext/schema/init.py (1 hunks)
- responder/models.py (7 hunks)
- responder/routes.py (6 hunks)
- setup.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
- responder/ext/schema/init.py
🔇 Additional comments (11)
responder/routes.py (4)
125-125
: Type ignore comment is appropriate.The
# type: ignore[attr-defined]
comment is correctly used here as mypy cannot verify the existence of the status code attribute at runtime. This is a common pattern when working with Starlette's HTTPException.
139-139
: Type ignore comment is appropriate.The
# type: ignore[attr-defined]
comment is correctly used here for the status code assignment, maintaining consistency with similar patterns in the codebase.
259-259
: LGTM! The dictionary update is more explicit and type-safe.The change to use
update({route: app})
instead ofupdate(route, app)
makes the key-value relationship clearer and aligns well with the type annotation.
293-298
:⚠️ Potential issueAddress the FIXME comment while verifying the error handling.
While the
# type: ignore[attr-defined]
comment is appropriate, there's an unaddressed FIXME comment that needs attention. The error handling here seems minimal, and the response object is created but not used (marked with noqa: F841).Consider enhancing the error handling:
async def default_response(self, scope, receive, send): if scope["type"] == "websocket": websocket_close = WebSocketClose() await websocket_close(scope, receive, send) return request = Request(scope, receive) response = Response(request, formats=get_formats()) response.status_code = status_codes.HTTP_404 # type: ignore[attr-defined] await response(scope, receive, send)Let's verify if this pattern is consistent across the codebase:
responder/models.py (5)
110-110
: LGTM: Proper type annotation for headers dictionary.The type annotation
CaseInsensitiveDict
correctly specifies the type of the headers dictionary, improving type safety.
153-153
: LGTM: Proper type annotation for cookie parsing.The type annotation
SimpleCookie
correctly specifies the type of the cookie parser, improving type safety.
242-255
: LGTM: Improved error handling and type safety in media processing.The changes properly handle different format types with appropriate error messages:
- Validates string formats against available formatters
- Verifies callable formats
- Raises clear error messages for invalid inputs
289-290
: LGTM: Proper type annotations for Response class attributes.The type annotations are correct and improve type safety:
status_code: t.Union[int, None]
properly handles the nullable status codecookies: SimpleCookie
correctly specifies the cookie container typeAlso applies to: 300-300
380-382
: LGTM: Improved type safety and error handling in response generation.The changes enhance reliability:
- Proper type annotation for response class selection
- Runtime validation prevents undefined status codes from propagating
Also applies to: 388-390
responder/api.py (2)
373-373
: Verify the removal of debug parameter from uvicorn.run.The
debug
parameter has been removed fromuvicorn.run()
but is still accepted in the method signature and used in therun()
method. This could lead to confusion as the parameter would have no effect when usingserve()
directly.Let's verify the impact:
#!/bin/bash # Check if debug parameter is used consistently across the codebase echo "Searching for debug parameter usage in serve/run methods:" rg "def (serve|run).*debug.*:" -A 5 echo "Checking uvicorn.run usage patterns:" rg "uvicorn\.run.*debug.*" -A 2Please clarify:
- Should the debug parameter be removed from the serve method signature?
- Or should it be passed to uvicorn.run?
224-224
: LGTM: Type ignore is appropriate here.The type ignore for
status_code
is necessary as mypy cannot determine that it's a valid attribute. This is a known limitation with Starlette's type definitions.Let's verify if this is a common pattern across the codebase:
✅ Verification successful
The previous search might have failed due to the specific pattern. Let's try these broader searches to understand the usage pattern of status codes and verify if the type ignore is appropriate.
Type ignore for status_code is consistent with codebase patterns
Based on the search results, the type ignore for
status_code
is appropriate and consistent with the codebase's patterns. We can see similar type ignores forstatus_code
assignments across multiple files:
responder/routes.py
:response.status_code = status_codes.HTTP_200 # type: ignore[attr-defined]
responder/ext/schema/__init__.py
:resp.status_code = status_codes.HTTP_200 # type: ignore[attr-defined]
This is a known limitation with Starlette's type definitions, and the codebase consistently handles it with type ignores.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for similar status_code assignments to understand the pattern rg "status_code.*=.*status_codes\.HTTP_" -A 2Length of output: 641
Script:
#!/bin/bash # Let's try a more comprehensive search for status_code assignments rg "\.status_code\s*=" -A 2 # Also search for HTTP status code imports and usage rg "from.*status_codes.*import|status_codes\.HTTP" -A 2 # Let's also check the specific file cat responder/api.pyLength of output: 20666
responder/routes.py
Outdated
@@ -207,7 +208,7 @@ class Router: | |||
def __init__(self, routes=None, default_response=None, before_requests=None): | |||
self.routes = [] if routes is None else list(routes) | |||
# [TODO] Make its own router | |||
self.apps = {} | |||
self.apps: t.Dict[str, t.Any] = {} |
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.
🛠️ Refactor suggestion
Consider using a more specific type annotation for apps
.
While t.Dict[str, t.Any]
is technically correct, it's quite permissive. Based on the usage in the mount
method and the docstring "Mounts ASGI / WSGI applications", consider using a more specific type like:
from typing import Union, Callable, Protocol
class ASGIApp(Protocol):
async def __call__(self, scope: dict, receive: Callable, send: Callable) -> None: ...
apps: t.Dict[str, Union[ASGIApp, 'WSGIApplication']]
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.
That's a good suggestion. I will try, thanks.
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.
@amotl, glad you found my suggestion helpful! Let me know if you have any questions or need further assistance.
/\_/\
( o.o )
> ^ <
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.
I tried, but mypy will complain then:
responder/routes.py:352: error: Incompatible types in "await" (actual type "Awaitable[None] | Iterable[bytes]", expected type "Awaitable[Any]") [misc]
responder/routes.py:352: error: Too many arguments [call-arg]
Found 2 errors in 1 file (checked 18 source files)
Error: Sequence aborted after failed subtask 'lint[3]'
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.
@amotl, it appears that the type annotations I suggested for apps
are causing mypy to raise errors because app
can be either an ASGI application (awaitable) or a WSGI application (non-awaitable). This leads to type inconsistencies when attempting to await app(scope, receive, send)
.
To address this, we can adjust the type annotations to accurately reflect the possible types of app
and modify the code to handle both cases explicitly. Here's a revised approach:
-
Update the type annotations:
from typing import Union, Callable, Awaitable, Any ASGIApp = Callable[[dict, Callable, Callable], Awaitable[None]] WSGIApp = Callable[..., Any] # WSGI applications accept 'environ' and 'start_response' apps: t.Dict[str, Union[ASGIApp, WSGIApp]]
-
Modify the
__call__
method to handle both ASGI and WSGI apps:async def __call__(self, scope, receive, send): # ... existing code ... # Call into a submounted app, if one exists. for path_prefix, app in self.apps.items(): if path.startswith(path_prefix): scope["path"] = path[len(path_prefix) :] scope["root_path"] = root_path + path_prefix if asyncio.iscoroutinefunction(app): # ASGI application await app(scope, receive, send) else: # WSGI application app = WSGIMiddleware(app) await app(scope, receive, send) return # ... existing code ...
This way, we explicitly check if app
is an awaitable ASGI application or a regular WSGI application and handle each case accordingly. This should resolve the mypy errors by ensuring type consistency.
Let me know if this helps or if you have further questions.
(\_ _/)
( •_• )
/ >💭< \
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.
This definition works well:
from starlette.types import ASGIApp
self.apps: t.Dict[str, ASGIApp] = {}
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.
@amotl, I'm glad to hear that using self.apps: t.Dict[str, ASGIApp] = {}
works well for you! If your application only needs to handle ASGI applications, this type annotation is appropriate and keeps the code straightforward. Thanks for sharing your solution.
✏️ Learnings added
Learnt from: amotl
PR: kennethreitz/responder#560
File: responder/routes.py:0-0
Timestamp: 2024-10-30T21:57:29.151Z
Learning: In `responder/routes.py`, when only ASGI applications are being mounted, it's acceptable to annotate `self.apps` as `t.Dict[str, ASGIApp]` in the `Router` class.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
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.
Thanks for your suggestion. I've deferred it to a dedicated issue, so it will not be forgotten.
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.
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.
Auto Pull Request Review from LlamaPReview
1. Overview
1.1 PR Summary
- Purpose: Integrate
mypy
type checking into theresponder
project to improve code quality and type safety. - Key Components Modified:
pyproject.toml
,responder/api.py
,responder/ext/schema/__init__.py
,responder/models.py
,responder/routes.py
, andsetup.py
. - Impact Assessment: Enhances code maintainability, reduces runtime errors, and improves overall code quality.
1.2 Architecture Changes
- System Design Modifications: Introduction of static type checking using
mypy
. - Component Interactions: Updates to the CI/CD pipeline to include
mypy
checks. - Integration Points: Changes primarily affect the
responder
module and the CI/CD pipeline.
2. Detailed Technical Analysis
2.1 Code Logic Deep-Dive
Core Logic Changes
responder/models.py - Response
class
- Submitted PR Code:
if self.status_code is None: raise RuntimeError("HTTP status code has not been defined")
- Analysis:
- Logic Flow Evaluation: The status code validation logic is duplicated in the
__call__
andok
methods. - Edge Cases Consideration: Handling of
status_code
in theResponse
class. - Potential Issues/Bugs: Duplicated logic can lead to inconsistencies and maintenance issues.
- Logic Flow Evaluation: The status code validation logic is duplicated in the
- LlamaPReview Suggested Improvements:
class Response: def _validate_status_code(self) -> None: if self.status_code is None: raise RuntimeError("HTTP status code has not been defined") async def __call__(self, scope, receive, send): body, headers = await self.body if self.headers: headers.update(self.headers) self._validate_status_code() response = response_cls(body, status_code=self.status_code, headers=headers) self._prepare_cookies(response) await response(scope, receive, send) @property def ok(self): self._validate_status_code() return 200 <= self.status_code < 300
Algorithm & Data Structure Analysis
- Complexity Analysis: The changes introduce minimal additional complexity due to type annotations and validation logic.
- Performance Implications: Minimal impact on performance. The main impact will be on the build times due to type checking.
- Memory Usage Considerations: No significant memory usage concerns identified.
2.2 Implementation Quality
- Code Organization and Structure: The code is generally well-organized. However, there are inconsistencies in type annotations.
- Design Patterns Usage: Follows best practices for type annotations as outlined in PEP 484.
- Error Handling Approach: Improved with the introduction of type checking.
- Resource Management: No potential memory leaks or resource management issues identified.
3. Critical Findings
3.1 Potential Issues
-
🔴 Critical Issues
- Issue Description: Inconsistent type annotations across different files.
- Impact: Can lead to confusion and potential type errors.
- Recommendation: Standardize the use of type annotations across the project.
-
🟡 Warnings
- Warning Description: The CI/CD pipeline may fail due to new type checking rules.
- Potential Risks: Type errors during the build process.
- Suggested Improvements: Ensure that all type annotations are correct and that the CI pipeline is configured to handle type errors gracefully.
3.2 Code Quality Concerns
- Maintainability Aspects: The introduction of type checking will improve maintainability by catching type-related errors early.
- Readability Issues: Inconsistent type annotations can reduce readability.
- Performance Bottlenecks: Minimal impact on performance. The main impact will be on the build times due to type checking.
4. Security Assessment
4.1 Security Considerations
- Authentication/Authorization Impacts: None identified.
- Data Handling Concerns: None identified.
- Input Validation: No changes to input validation mechanisms.
- Security Best Practices: Follow best practices for type annotations and error handling.
4.2 Vulnerability Analysis
- Potential Security Risks: None identified.
- Mitigation Strategies: Ensure proper handling of type errors in the CI/CD pipeline.
- Security Testing Requirements: Test the integration of
mypy
with the CI/CD pipeline.
5. Testing Strategy
5.1 Test Coverage
- Unit Test Analysis: Ensure all type-annotated functions are tested.
- Integration Test Requirements: Test the integration of
mypy
with the CI/CD pipeline. - Edge Cases Coverage: Test the handling of
status_code
in theResponse
class.
5.2 Test Recommendations
Suggested Test Cases
def test_response_status_code_validation():
response = Response(req=None, formats=None)
with pytest.raises(RuntimeError):
response.ok
with pytest.raises(RuntimeError):
await response(scope=None, receive=None, send=None)
- Coverage Improvements: Aim for 100% coverage of type-annotated functions.
- Performance Testing Needs: Measure the impact of type checking on build times.
6. Documentation & Maintenance
6.1 Documentation Requirements
- API Documentation Updates: None identified.
- Architecture Documentation: Update documentation to reflect
mypy
configuration. - Configuration Changes: Ensure documentation includes running
mypy
. - Usage Examples: Provide examples of type annotations and how to configure
mypy
.
6.2 Maintenance Considerations
- Long-term Maintainability: The introduction of type checking can help reduce technical debt by making the codebase more robust and easier to maintain.
- Technical Debt Assessment: If type annotations are not kept up-to-date, this could introduce new forms of technical debt.
- Monitoring Requirements: Monitor for type errors in the CI/CD pipeline.
7. Deployment & Operations
7.1 Deployment Impact
- Deployment Strategy: Ensure deployment instructions include running
mypy
. - Rollback Plan: If the CI/CD pipeline fails due to type errors, roll back the changes and address the issues.
- Configuration Changes: Update the CI/CD pipeline to include
mypy
checks.
7.2 Operational Considerations
- Monitoring Requirements: Monitor the CI/CD pipeline for type errors.
- Performance Metrics: Measure the impact of type checking on build times.
- Resource Utilization: Increased CPU usage during the type checking process.
8. Summary & Recommendations
8.1 Key Action Items
- Fix type annotations: High priority, estimated 2 hours.
- Update CI/CD pipeline: Medium priority, estimated 1 hour.
- Standardize type annotations: Low priority, estimated 1 hour.
8.2 Future Considerations
- Long-term Improvements: Gradually introduce type annotations and monitor the CI/CD pipeline for issues.
- Technical Debt Items: Keep type annotations up-to-date to avoid introducing new forms of technical debt.
- Scalability Considerations: No significant scalability considerations identified.
About
This patch enables mypy to be invoked on
poe check
, thus also slotting it into CI checks on GHA.Status
It will need more work after other feature patches have been merged. Hereby handing this in as a questionFurther information is requested
asking for feedback if you appreciate or discourage this improvement to the code base.