- 
                Notifications
    You must be signed in to change notification settings 
- Fork 98
Fix errors reported by mypy #490
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
Conversation
Fixes one mypy-detected error: Type of __all__ must be "Sequence[str]", not "List[object]" Towards resolving #489
Resolves the error Incompatible types in assignment (expression has type "bool", target has type "Collection[Any]")
        
          
                planet/clients/data.py
              
                Outdated
          
        
      | request_json: typing.Dict[str, typing.Any] = { | ||
| 'name': name, 'filter': search_filter, 'item_types': item_types | ||
| } | ||
| # QUESTION: can we just set the value to True or False above? | 
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.
We have a test that doesn't expect __daily_email_enabled: False, but I wonder if the API would handle this?
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.
The API reference claims that the type of this parameter is a boolean so I imagine it would handle True/False values. Is that the question here?
        
          
                planet/clients/data.py
              
                Outdated
          
        
      |  | ||
| # TODO: validate item_types | ||
| request_json = { | ||
| request_json: typing.Dict[str, typing.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.
Without this hint, mypy diagnoses request_json's type as Dict[str, Collection[Any]] because name, search_filter, and item_types are all collections, and then complains when we try to add a bool item, which is not a collection.
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.
ahh interesting! good catch. I wonder if we want to make this a custom type, eg JSONType and move it over, along with AuthType to a new types module?
Added a new AuthType alias for httpx.Auth, added a missing abstract method.
|  | ||
| @abc.abstractmethod | ||
| def to_dict(self) -> dict: | ||
| pass | 
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.
Resolves
planet/auth.py:132: error: "Auth" has no attribute "to_dict"
| BASE_URL = f'{PLANET_BASE_URL}/v0/auth' | ||
| ENV_API_KEY = 'PL_API_KEY' | ||
|  | ||
| AuthType = httpx.Auth | 
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.
Resolves
planet/http.py:123: error: Argument "auth" to "AsyncClient" has incompatible type "planet.auth.Auth"; expected "Union[Tuple[Union[str, bytes], Union[str, bytes]], Callable[[Request], Request], httpx._auth.Auth, None]"
| ''' | ||
| variable_name = variable_name or ENV_API_KEY | ||
| api_key = os.getenv(variable_name) | ||
| api_key = os.getenv(variable_name, '') | 
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.
Resolves
planet/auth.py:85: error: Argument 1 to "APIKeyAuth" has incompatible type "Optional[str]"; expected "str"
The APIKeyAuth constructor does not take None as an argument (key: str) but we might pass it None if there's nothing in the environment. Instead, we'll pass an empty string.
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 is a nice catch
| def from_login(email: str, password: str, base_url: str = None) -> AuthType: | ||
| def from_login(email: str, | ||
| password: str, | ||
| base_url: str = None) -> AuthType: | 
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.
Carried over formatting.
| order type. | ||
| ''' | ||
| details = {'name': name, 'products': products} | ||
| details: Dict[str, Any] = {'name': name, 'products': products} | 
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.
mypy requires us to be more careful about dict typing.
| order_type = specs.validate_order_type(order_type) | ||
| details['order_type'] = order_type | ||
| validated_order_type = specs.validate_order_type(order_type) | ||
| details['order_type'] = validated_order_type | 
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.
In general, mypy discourages reassigning names, and not without reason because it can be a source of bugs.
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.
Oh! yeah, I can see that. nice catch.
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 reassign names a lot and it's a hard habit to break 😆
        
          
                planet/order_request.py
              
                Outdated
          
        
      | product_bundle = ','.join([product_bundle, fallback_bundle]) | ||
| validated_fallback_bundle = specs.validate_bundle(fallback_bundle) | ||
| specs.validate_item_type(item_type, validated_fallback_bundle) | ||
| validated_product_bundle = ','.join([validated_product_bundle, validated_fallback_bundle]) | 
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.
Here, though, mypy's analyzer can't find that anything on the right side will be None, so it doesn't care if we reassign.
And ignore mypy warnings about modules with no typing or stubs.
|  | ||
| self.bar.refresh() | ||
| if self.bar is not None: | ||
| self.bar.refresh() | 
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.
mypy noticed some cases where self.bar could be None and we would try to call its methods.
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 is cool as heck. I should try mypy
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.
awesome catch. this would probably have bubbled up as a bug eventually.
| @jreiberkyle @mkshah605 @kevinlacaille this is 6 commits, 9 files. It might look like a long review, but it's only a few lines per file. The TLDR: a few commits fix subtle bugs that our tests were not triggering (static analysis for the win!), the rest of the commits fix improper use of type hints or reconcile our code with mypy's stricter view of typing. I think we should merge this right away if we're going to continue to use type hints in the project. And I think we probably will, users increasingly expect them. | 
| 'order_request', | ||
| 'reporting', | ||
| 'Session', | ||
| ] | 
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.
__all__ requires strings, not objects.
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.
its great to have static typing in the python library and turned out to be much easier than I had expected.
| ''' | ||
| variable_name = variable_name or ENV_API_KEY | ||
| api_key = os.getenv(variable_name) | ||
| api_key = os.getenv(variable_name, '') | 
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 is a nice catch
        
          
                planet/clients/data.py
              
                Outdated
          
        
      | request_json: typing.Dict[str, typing.Any] = { | ||
| 'name': name, 'filter': search_filter, 'item_types': item_types | ||
| } | ||
| # QUESTION: can we just set the value to True or False above? | 
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.
The API reference claims that the type of this parameter is a boolean so I imagine it would handle True/False values. Is that the question here?
        
          
                planet/clients/data.py
              
                Outdated
          
        
      |  | ||
| # TODO: validate item_types | ||
| request_json = { | ||
| request_json: typing.Dict[str, typing.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.
ahh interesting! good catch. I wonder if we want to make this a custom type, eg JSONType and move it over, along with AuthType to a new types module?
| order_type = specs.validate_order_type(order_type) | ||
| details['order_type'] = order_type | ||
| validated_order_type = specs.validate_order_type(order_type) | ||
| details['order_type'] = validated_order_type | 
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.
Oh! yeah, I can see that. nice catch.
|  | ||
| self.bar.refresh() | ||
| if self.bar is not None: | ||
| self.bar.refresh() | 
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.
awesome catch. this would probably have bubbled up as a bug eventually.
Removes a conditional statement and eliminates one of the original mypy errors.
| @sgillies can you please also add how to use mypy into CONTRIBUTING.md? | 
| Done in ff57b41. | 
Resolves #489
@jreiberkyle @mkshah605 @kevinlacaille this is 6 commits, 9 files. It might look like a long review, but it's only a few lines per file. The TLDR: a few commits fix subtle bugs that our tests were not triggering (static analysis for the win!), the rest of the commits fix improper use of type hints or reconcile our code with mypy's stricter view of typing. I think we should merge this right away if we're going to continue to use type hints in the project. And I think we probably will, users increasingly expect them.