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

Inline typechecking for exceptions and add typechecking for collections #2115

Merged
merged 14 commits into from
Mar 9, 2021

Conversation

haikuginger
Copy link
Contributor

This is a first step towards moving towards inline types for all of urllib3. For now, this just fixes and extends the existing types for the exceptions module, but adds typing for the _collections and utils.response modules.

Note that because not all of our codebase is covered by typechecking, we can be pretty sure that these types are internally consistent, but not that they're correct. We'll need a lot more type coverage before we can be sure of that. For now, existing tests pass with minimal modifications, which is possibly the best we can do.

@codecov
Copy link

codecov bot commented Dec 18, 2020

Codecov Report

Merging #2115 (07671b7) into main (dc6284c) will decrease coverage by 0.13%.
The diff coverage is 97.87%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2115      +/-   ##
==========================================
- Coverage   99.95%   99.82%   -0.14%     
==========================================
  Files          25       26       +1     
  Lines        2221     2260      +39     
==========================================
+ Hits         2220     2256      +36     
- Misses          1        4       +3     
Impacted Files Coverage Δ
src/urllib3/_compat.py 0.00% <0.00%> (ø)
src/urllib3/_collections.py 100.00% <100.00%> (ø)
src/urllib3/exceptions.py 100.00% <100.00%> (ø)
src/urllib3/response.py 100.00% <100.00%> (ø)
src/urllib3/util/response.py 100.00% <100.00%> (ø)
src/urllib3/util/util.py 95.45% <0.00%> (+0.45%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dc6284c...07671b7. Read the comment docs.

defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect)
)
]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I figured since we're going to start protecting this with typechecking we could remove the runtime check on if attributes exist. Can revert though.

Copy link
Member

Choose a reason for hiding this comment

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

This is all fine since we have the isinstance check, so we don't have to worry about users sending weird objects into this function

src/urllib3/util/response.py Show resolved Hide resolved
src/urllib3/_collections.py Show resolved Hide resolved
src/urllib3/_collections.py Show resolved Hide resolved
Copy link
Member

@sethmlarson sethmlarson 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 this, some early comments more coming later.

src/urllib3/_collections.py Outdated Show resolved Hide resolved
src/urllib3/_collections.py Show resolved Hide resolved
src/urllib3/_collections.py Show resolved Hide resolved
src/urllib3/_collections.py Outdated Show resolved Hide resolved
src/urllib3/_collections.py Outdated Show resolved Hide resolved
Base automatically changed from master to main January 16, 2021 20:06
@haikuginger haikuginger force-pushed the haikuginger/inline-typing-collections-exceptions branch from 4c6d050 to d95d9db Compare February 1, 2021 01:27
.coveragerc Outdated Show resolved Hide resolved
@franekmagiera
Copy link
Member

Hi, took a look at _collections.py. Maybe it would make sense to include a comment that when Mapping or Iterable is passed to HTTPHeaderDict it is assumed that it is Mapping[str, str] and iterable of string pairs? Small thing, but the only one that caught my attention. Overall it looks OK to me, nice work :)

@franekmagiera
Copy link
Member

Also, regarding making typing extensions a runtime dependency - if #1985 was to be implemented using Protocol and not abc, wouldn't it be necessary to have typing extensions as a runtime dependency?

@haikuginger
Copy link
Contributor Author

Also, regarding making typing extensions a runtime dependency - if #1985 was to be implemented using Protocol and not abc, wouldn't it be necessary to have typing extensions as a runtime dependency?

Are you talking about how we describe the API? If so, then not strictly speaking. If we implemented a protocol in an if TYPE_CHECKING: block, we could refer to it via string annotations in places where it's returned or needs to be passed in. E.g.:


if TYPE_CHECKING:
    class HasSomeValuesInAList(Protocol):
        that_list_i_told_you_about: List[int]

@dataclass
class ImplementationOfAbove:
    some_other_thing: str
    that_list_i_told_you_about: List[int]

def does_stuff_with_those_things(carries_vals: "HasSomeValuesInAList") -> None:
    for item in carries_vals.that_list_i_told_you_about:
        print(item)

# Valid
does_stuff_with_those_things(ImplementationOfAbove("the string", [1, 2, 3, 4, 5]))

Using string annotations results in a ForwardRef being used rather than the actual class in question, which means that the actual class in question can not exist at runtime and it'll be fine—as long as it's there when the typechecker goes looking.

@haikuginger haikuginger force-pushed the haikuginger/inline-typing-collections-exceptions branch from 1dc707a to d80dd29 Compare March 1, 2021 17:48
@haikuginger
Copy link
Contributor Author

Tagging @SethMichaelLarson for re-review. I think this is ready to merge.

@sethmlarson sethmlarson mentioned this pull request Mar 2, 2021
27 tasks
Copy link
Member

@sethmlarson sethmlarson 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 changes, more comments for you!

src/urllib3/_collections.py Outdated Show resolved Hide resolved
src/urllib3/_collections.py Show resolved Hide resolved
src/urllib3/_collections.py Outdated Show resolved Hide resolved
...

@overload
def getlist(self, key: str, default: List[str]) -> List[str]:
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't this override need to be Union[List[str], DefaultType where DefaultType is whatever type default is?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, if we want to support some default that isn't List[str], we'd need to do this:

@overload
def getlist(self, key: str, default: _DT) -> Union[List[str], _DT]]: ...

(in which case Union[List[str], _DT] collapses to List[str] in situations where _DT can be proven to be List[str])

The question is whether we want to support passing a default that isn't List[str]; I can take a look through the existing codebase to see what we do and where (the most likely case is that we pass in None in some places), and at typeshed to see what they do for builtins that accept defaults.

src/urllib3/_collections.py Outdated Show resolved Hide resolved
src/urllib3/_collections.py Show resolved Hide resolved
src/urllib3/_collections.py Outdated Show resolved Hide resolved
Copy link
Member

@sethmlarson sethmlarson left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for moving this mountain! 🎉

@sethmlarson sethmlarson merged commit 6d799ce into main Mar 9, 2021
@sethmlarson sethmlarson deleted the haikuginger/inline-typing-collections-exceptions branch March 9, 2021 02:16
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.

None yet

4 participants