Skip to content

🚨 Cover middleware/wsgi.py on mypy #1075

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

Merged
merged 15 commits into from
Jun 23, 2021
Merged

Conversation

Vibhu-Agarwal
Copy link
Contributor

Part of #998
Extends #1018

I've tried to solve most of the issues, but some still remain - not sure how to solve them.

@Vibhu-Agarwal
Copy link
Contributor Author

Not sure if this commit ^^^ is correct.
Will revert, if it's not.

Comment on lines 103 to 104
message: HTTPRequestEvent = await receive()
body = message.get("body", b"")
Copy link
Contributor Author

@Vibhu-Agarwal Vibhu-Agarwal Jun 9, 2021

Choose a reason for hiding this comment

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

Before the change, it was throwing this error:

uvicorn/middleware/wsgi.py:103: error: TypedDict "HTTPDisconnectEvent" has no key 'body'  [misc]
uvicorn/middleware/wsgi.py:103: error: TypedDict "WebsocketConnectEvent" has no key 'body'  [misc]
uvicorn/middleware/wsgi.py:103: error: TypedDict "WebsocketReceiveEvent" has no key 'body'  [misc]
uvicorn/middleware/wsgi.py:103: error: TypedDict "WebsocketDisconnectEvent" has no key 'body'  [misc]
uvicorn/middleware/wsgi.py:103: error: TypedDict "LifespanStartupEvent" has no key 'body'  [misc]
uvicorn/middleware/wsgi.py:103: error: TypedDict "LifespanShutdownEvent" has no key 'body'  [misc]

Copy link
Member

Choose a reason for hiding this comment

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

The http.disconnect never gets here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's exactly what was bugging me 😅
Most probably http.disconnect could get here.
But if I remove the type annotation from message, the body = message.get("body", b"") line throws out the errors.
Not sure how to resolve that then.

PS. The same goes for body_message a couple of lines below that.

Copy link
Member

@Kludex Kludex left a comment

Choose a reason for hiding this comment

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

Thanks for the PR @Vibhu-Agarwal ! 😃

I've added some comments, can you check them, please?

Comment on lines 103 to 104
message: HTTPRequestEvent = await receive()
body = message.get("body", b"")
Copy link
Member

Choose a reason for hiding this comment

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

The http.disconnect never gets here?

@euri10
Copy link
Member

euri10 commented Jun 10, 2021

I've not looked at this but you can maybe take inspiration from #1049 where I typed everything in the same module I think

@Vibhu-Agarwal Vibhu-Agarwal requested a review from Kludex June 10, 2021 20:07
self.send_queue.append(
{"type": "http.response.body", "body": chunk, "more_body": True}
)
def wsgi(self, environ: Dict, start_response: Awaitable[None]) -> None:
Copy link
Member

Choose a reason for hiding this comment

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

Once #1067 is merged (which is soon !) there will be a _types.py you can use for typing this

Copy link
Member

@Kludex Kludex left a comment

Choose a reason for hiding this comment

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

We're almost there! I've added some comments, do you mind taking a look @Vibhu-Agarwal ?

Thanks for your help so far!

if corrected_name in environ:
value = environ[corrected_name] + "," + value
environ[corrected_name] = value
corrected_name_environ = environ[corrected_name]
Copy link
Member

Choose a reason for hiding this comment

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

This looks a little too much just to satisfy mypy 🤔

Copy link
Member

Choose a reason for hiding this comment

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

Should we just ignore it here?

Copy link
Member

Choose a reason for hiding this comment

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

lgtm

status_code, _ = status.split(" ", 1)
status_code = int(status_code)
status_code_str, _ = status.split(" ", 1)
status_code: int = int(status_code_str)
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to add the annotation here? 🤔

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I guess we needed it before the renaming.

if corrected_name in environ:
value = environ[corrected_name] + "," + value
environ[corrected_name] = value
corrected_name_environ = environ[corrected_name]
Copy link
Member

Choose a reason for hiding this comment

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

lgtm

Copy link
Member

@euri10 euri10 left a comment

Choose a reason for hiding this comment

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

this lgtm @Vibhu-Agarwal thanks a lot
I let @Kludex finish it :)

edit: oups didnt see the CI was failing, will have to wait >_)

@euri10
Copy link
Member

euri10 commented Jun 23, 2021

you can use this patch @Vibhu-Agarwal I think this solves the rest

Index: tests/middleware/test_wsgi.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/tests/middleware/test_wsgi.py b/tests/middleware/test_wsgi.py
--- a/tests/middleware/test_wsgi.py	(revision 7610a04a8be1219b2b48eff20e73ad0049884c45)
+++ b/tests/middleware/test_wsgi.py	(revision 6b84705a15ace9d662a49f15921c54bdfd8287c1)
@@ -3,7 +3,7 @@
 
 import httpx
 import pytest
-from asgiref.typing import HTTPScope
+from asgiref.typing import HTTPRequestEvent, HTTPScope
 
 from uvicorn._types import Environ, StartResponse
 from uvicorn.middleware.wsgi import WSGIMiddleware, build_environ
@@ -16,7 +16,7 @@
         ("Content-Type", "text/plain; charset=utf-8"),
         ("Content-Length", str(len(output))),
     ]
-    start_response(status, headers)
+    start_response(status, headers, None)
     return [output]
 
 
@@ -27,7 +27,7 @@
         ("Content-Type", "text/plain; charset=utf-8"),
         ("Content-Length", str(len(output))),
     ]
-    start_response(status, headers)
+    start_response(status, headers, None)
     return [output]
 
 
@@ -45,7 +45,7 @@
             ("Content-Type", "text/plain; charset=utf-8"),
             ("Content-Length", str(len(output))),
         ]
-        start_response(status, headers, exc_info=sys.exc_info())
+        start_response(status, headers, sys.exc_info())  # type: ignore[arg-type]
         return [output]
 
 
@@ -108,7 +108,12 @@
         "root_path": "/文",
         "query_string": b"a=123&b=456",
         "headers": [(b"key", b"value1"), (b"key", b"value2")],
+    }  # type: ignore[typeddict-item]
+    message: HTTPRequestEvent = {
+        "type": "http.request",
+        "body": b"",
+        "more_body": False,
     }
-    environ = build_environ(scope, b"", b"")
+    environ = build_environ(scope, message, b"")
     assert environ["PATH_INFO"] == "/文".encode("utf8").decode("latin-1")
     assert environ["HTTP_KEY"] == "value1,value2"
Index: uvicorn/_types.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/uvicorn/_types.py b/uvicorn/_types.py
--- a/uvicorn/_types.py	(revision 7610a04a8be1219b2b48eff20e73ad0049884c45)
+++ b/uvicorn/_types.py	(revision 6b84705a15ace9d662a49f15921c54bdfd8287c1)
@@ -9,4 +9,6 @@
 StartResponse = typing.Callable[
     [str, typing.Iterable[typing.Tuple[str, str]], typing.Optional[ExcInfo]], None
 ]
-WSGIApp = typing.Callable[[Environ, StartResponse], typing.Iterable[bytes]]
+WSGIApp = typing.Callable[
+    [Environ, StartResponse], typing.Union[typing.Iterable[bytes], BaseException]
+]

@Vibhu-Agarwal
Copy link
Contributor Author

Vibhu-Agarwal commented Jun 23, 2021

Failing on 3.6 and 3.7 🤔

@euri10
Copy link
Member

euri10 commented Jun 23, 2021 via email

@Vibhu-Agarwal
Copy link
Contributor Author

Vibhu-Agarwal commented Jun 23, 2021

Unable to figure out the fix 😕
Import doesn't seem like the issue here, as it's coming directly from asgiref where they're checking the version and aptly importing from typing/typing_extensions.
For some reason, # type: ignore isn't working 🤔

@euri10
Copy link
Member

euri10 commented Jun 23, 2021

you can fill the scope too

    scope: HTTPScope = {
        "type": "http",
        "asgi": {"version": "3.0", "spec_version": "2.0"},
        "scheme": "http",
        "http_version": "1.1",
        "method": "GET",
        "path": "/文",
        "raw_path": b"/\xe6\x96\x87",
        "root_path": "/文",
        "query_string": b"a=123&b=456",
        "client": None,
        "server": None,
        "headers": [(b"key", b"value1"), (b"key", b"value2")],
        "extensions": {},
    }

@Vibhu-Agarwal
Copy link
Contributor Author

Thanks for the reviews and support 👍
Cc @euri10 @Kludex

@euri10 euri10 merged commit 467e032 into encode:master Jun 23, 2021
@euri10
Copy link
Member

euri10 commented Jun 23, 2021

thanks a lot @Vibhu-Agarwal !

@Vibhu-Agarwal Vibhu-Agarwal deleted the jkl_1018 branch June 23, 2021 16:26
Kludex pushed a commit that referenced this pull request Nov 17, 2021
* add types to wsgi module

* Add middleware/wsgi.py to setup.cfg

* Smoothen out a few (mypy-related) bugs

I don't know how to solve the remaining ones

* Small Fix: use HTTPRequestEvent

* Apply suggestions from PR review

* Remove all mypy issues

Taking ideas from: https://github.com/encode/uvicorn/blob/dd85cdacf154529ea1c3d12b5bda7808673979f2/uvicorn/middleware/wsgi.py

* Adjusting w.r.t. to #1067

* Adjusting w.r.t. to #1067

* Applied suggestions from PR review

* Fixed remaining test_wsgi.py mypy issues

* Trying by removing "[typeddict-item]" beside "type: ignore"

* Revert previous commit

* Final fix ... yaayyy!

Co-authored-by: Jaakko Lappalainen <[email protected]>
Kludex pushed a commit to sephioh/uvicorn that referenced this pull request Oct 29, 2022
* add types to wsgi module

* Add middleware/wsgi.py to setup.cfg

* Smoothen out a few (mypy-related) bugs

I don't know how to solve the remaining ones

* Small Fix: use HTTPRequestEvent

* Apply suggestions from PR review

* Remove all mypy issues

Taking ideas from: https://github.com/encode/uvicorn/blob/dd85cdacf154529ea1c3d12b5bda7808673979f2/uvicorn/middleware/wsgi.py

* Adjusting w.r.t. to encode#1067

* Adjusting w.r.t. to encode#1067

* Applied suggestions from PR review

* Fixed remaining test_wsgi.py mypy issues

* Trying by removing "[typeddict-item]" beside "type: ignore"

* Revert previous commit

* Final fix ... yaayyy!

Co-authored-by: Jaakko Lappalainen <[email protected]>
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.

4 participants