adafruit / Adafruit_CircuitPython_Requests

Requests-like interface for web interfacing
MIT License
51 stars 37 forks source link

Missing Type Annotations #78

Closed FoamyGuy closed 2 years ago

FoamyGuy commented 3 years ago

There are missing type annotations for some functions in this library.

The typing module does not exist on CircuitPython devices so the import needs to be wrapped in try/except to catch the error for missing import. There is an example of how that is done here:

try:
    from typing import List, Tuple
except ImportError:
    pass

Once imported the typing annotations for the argument type(s), and return type(s) can be added to the function signature. Here is an example of a function that has had this done already:

def wrap_text_to_pixels(
    string: str, max_width: int, font=None, indent0: str = "", indent1: str = ""
) -> List[str]:

If you are new to Git or Github we have a guide about contributing to our projects here: https://learn.adafruit.com/contribute-to-circuitpython-with-git-and-github

There is also a guide that covers our CI utilities and how to run them locally to ensure they will pass in Github Actions here: https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/check-your-code In particular the pages: Sharing docs on ReadTheDocs and Check your code with pre-commit contain the tools to install and commands to run locally to run the checks.

If you are attempting to resolve this issue and need help, you can post a comment on this issue and tag both @foamyguy and @kattni or reach out to us on Discord: https://adafru.it/discord in the #circuitpython-dev channel.

The following locations are reported by mypy to be missing type annotations:

tekktrik commented 2 years ago

Submitted PR #87 to address

FoamyGuy commented 2 years ago

closed by #87

kevincon commented 2 years ago

@FoamyGuy while working on #94 I saw there are still 42 mypy errors in adafruit_requests.py, so you might consider reopening this issue.

To reproduce, you can apply this diff to the pre-commit config on main (e.g. the run below was on 26b2411780f69edece156c25476359242446bac0):

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1b9fadc..f6745f9 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -40,3 +40,10 @@ repos:
         files: "^tests/"
         args:
         - --disable=missing-docstring,consider-using-f-string,duplicate-code
+- repo: https://github.com/pre-commit/mirrors-mypy
+  rev: v0.930
+  hooks:
+  - id: mypy
+    files: ^(adafruit_requests.py)
+    additional_dependencies:
+    - types-ujson

and then run:

(.env) gitpod /workspace/Adafruit_CircuitPython_Requests $ pre-commit run mypy --all-files
mypy.....................................................................Failed
- hook id: mypy
- exit code: 1

adafruit_requests.py:115: error: Need type annotation for "socket"
adafruit_requests.py:118: error: Need type annotation for "_headers" (hint: "_headers: Dict[<type>, <type>] = ...")
adafruit_requests.py:216: error: Argument 1 to "_recv_into" of "Response" has incompatible type "memoryview"; expected "bytearray"
adafruit_requests.py:230: error: Unsupported operand types for > ("int" and "None")
adafruit_requests.py:230: note: Left operand is of type "Optional[int]"
adafruit_requests.py:231: error: Incompatible types in assignment (expression has type "Optional[int]", variable has type "int")
adafruit_requests.py:261: error: Incompatible types in assignment (expression has type "int", variable has type "None")
adafruit_requests.py:266: error: Unsupported operand types for > ("int" and "None")
adafruit_requests.py:267: error: Incompatible types in assignment (expression has type "None", variable has type "int")
adafruit_requests.py:272: error: Unsupported operand types for - ("None" and "int")
adafruit_requests.py:272: error: Incompatible types in assignment (expression has type "int", variable has type "None")
adafruit_requests.py:321: error: Incompatible types in assignment (expression has type "str", variable has type "bytes")
adafruit_requests.py:322: error: Incompatible types in assignment (expression has type "str", variable has type "bytes")
adafruit_requests.py:324: error: Incompatible types in assignment (expression has type "int", variable has type "None")
adafruit_requests.py:345: error: Incompatible types in assignment (expression has type "bytes", variable has type "None")
adafruit_requests.py:345: error: Argument 1 to "join" of "bytes" has incompatible type "bytes"; expected "Iterable[Union[ByteString, memoryview]]"
adafruit_requests.py:345: note: Following member(s) of "bytes" have conflicts:
adafruit_requests.py:345: note:     Expected:
adafruit_requests.py:345: note:         def __iter__(self) -> Iterator[Union[ByteString, memoryview]]
adafruit_requests.py:345: note:     Got:
adafruit_requests.py:345: note:         def __iter__(self) -> Iterator[int]
adafruit_requests.py:346: error: Incompatible return value type (got "None", expected "bytes")
adafruit_requests.py:356: error: Incompatible types in assignment (expression has type "str", variable has type "None")
adafruit_requests.py:356: error: Argument 2 to "str" has incompatible type "Optional[str]"; expected "str"
adafruit_requests.py:357: error: Incompatible return value type (got "None", expected "str")
adafruit_requests.py:370: error: Incompatible types in assignment (expression has type "_RawResponse", variable has type "None")
adafruit_requests.py:373: error: Argument 1 to "load" has incompatible type "None"; expected "SupportsRead[Union[str, bytes]]"
adafruit_requests.py:377: error: "None" has no attribute "read"
adafruit_requests.py:383: error: The return type of a generator function should be "Generator" or one of its supertypes
adafruit_requests.py:413: error: Need type annotation for "_open_sockets" (hint: "_open_sockets: Dict[<type>, <type>] = ...")
adafruit_requests.py:414: error: Need type annotation for "_socket_free" (hint: "_socket_free: Dict[<type>, <type>] = ...")
adafruit_requests.py:477: error: Item "None" of "Optional[SSLContext]" has no attribute "wrap_socket"
adafruit_requests.py:535: error: "Dict[str, str]" has no attribute "encode"
adafruit_requests.py:537: error: No overload variant of "__getitem__" of "list" matches argument type "Dict[str, str]"
adafruit_requests.py:537: note: Possible overload variants:
adafruit_requests.py:537: note:     def __getitem__(self, SupportsIndex) -> Dict[str, str]
adafruit_requests.py:537: note:     def __getitem__(self, slice) -> List[Dict[str, str]]
adafruit_requests.py:537: note:     def __getitem__(self, SupportsIndex) -> Dict[str, str]
adafruit_requests.py:537: note:     def __getitem__(self, slice) -> List[Dict[str, str]]
adafruit_requests.py:537: note:     def __getitem__(self, SupportsIndex) -> Dict[str, str]
adafruit_requests.py:537: note:     def __getitem__(self, slice) -> List[Dict[str, str]]
adafruit_requests.py:537: note:     def __getitem__(self, SupportsIndex) -> Dict[str, str]
adafruit_requests.py:537: note:     def __getitem__(self, slice) -> List[Dict[str, str]]
adafruit_requests.py:545: error: Name "json_module" already defined (by an import)
adafruit_requests.py:583: error: Incompatible types in assignment (expression has type "Dict[<nothing>, <nothing>]", variable has type "Optional[List[Dict[str, str]]]")
adafruit_requests.py:600: error: Incompatible types in assignment (expression has type "str", variable has type "int")
adafruit_requests.py:615: error: Argument 5 to "_send_request" of "Session" has incompatible type "Optional[List[Dict[str, str]]]"; expected "List[Dict[str, str]]"
adafruit_requests.py:633: error: Incompatible types in assignment (expression has type "None", variable has type "socket")
adafruit_requests.py:659: error: Incompatible types in assignment (expression has type "Response", variable has type "None")
adafruit_requests.py:662: error: Incompatible types in assignment (expression has type "Response", variable has type "None")
adafruit_requests.py:697: error: Need type annotation for "_socket"
adafruit_requests.py:699: error: Need type annotation for "settimeout"
adafruit_requests.py:700: error: Need type annotation for "send"
adafruit_requests.py:701: error: Need type annotation for "recv"
adafruit_requests.py:702: error: Need type annotation for "close"
adafruit_requests.py:731: error: Argument 2 to "Session" has incompatible type "_FakeSSLContext"; expected "Optional[SSLContext]"
adafruit_requests.py:733: error: Argument 2 to "Session" has incompatible type "_FakeSSLContext"; expected "Optional[SSLContext]"
adafruit_requests.py:748: error: Item "None" of "Optional[Session]" has no attribute "request"
adafruit_requests.py:761: error: Item "None" of "Optional[Session]" has no attribute "request"
adafruit_requests.py:766: error: Item "None" of "Optional[Session]" has no attribute "request"
adafruit_requests.py:771: error: Item "None" of "Optional[Session]" has no attribute "request"
adafruit_requests.py:776: error: Item "None" of "Optional[Session]" has no attribute "request"
adafruit_requests.py:781: error: Item "None" of "Optional[Session]" has no attribute "request"
adafruit_requests.py:786: error: Item "None" of "Optional[Session]" has no attribute "request"
Found 49 errors in 1 file (checked 1 source file)

I saw that the number of errors decreases to 42 after #94.

FoamyGuy commented 2 years ago

@kevincon thanks for the heads up. It is okay for the library not to completely pass mypy testing at this point.

The main ones that we are looking to take care with the current effort are the "function missing type annotation" warnings.

We have not added mypy to the CI checks yet. When the time comes to do that (once we have most of the typing "low hanging fruit" done accross all libraries) then we'll have a discussion amongst the team to determine what settings and configuration we'll use for mypy when we add it to CI which may change which specific mypy warnings and how many of them we'll see on any given library.