Skip to content

Commit 72eb746

Browse files
authored
Fix errors reported by mypy (#490)
* Strings, not objects Fixes one mypy-detected error: Type of __all__ must be "Sequence[str]", not "List[object]" Towards resolving #489 * Fix __all__ in another module, use single quotes * Add typing to request dict Resolves the error Incompatible types in assignment (expression has type "bool", target has type "Collection[Any]") * Our auth.Auth isn't type-compatible with httpx.AsyncClient Added a new AuthType alias for httpx.Auth, added a missing abstract method. * Fix mypy errors in order_requests * Strictly guard against having no status bar in reporting.py And ignore mypy warnings about modules with no typing or stubs. * Always set email flag in search request Removes a conditional statement and eliminates one of the original mypy errors.
1 parent e4eabba commit 72eb746

File tree

10 files changed

+67
-36
lines changed

10 files changed

+67
-36
lines changed

noxfile.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@
33
nox.options.stop_on_first_error = True
44
nox.options.reuse_existing_virtualenvs = False
55

6-
nox.options.sessions = ['lint', 'test', 'coverage', 'docs']
6+
nox.options.sessions = ['lint', 'analyze', 'test', 'coverage', 'docs']
77

88
source_files = ("planet", "examples", "tests", "setup.py", "noxfile.py")
99

1010

11+
@nox.session
12+
def analyze(session):
13+
session.install(".[lint]")
14+
15+
session.run("mypy", "--ignore-missing", "planet")
16+
17+
1118
@nox.session
1219
def coverage(session):
1320
session.install("-e", ".[test]")

planet/__init__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
from . import order_request, reporting
1616
from .__version__ import __version__ # NOQA
1717
from .auth import Auth
18-
from .clients import DataClient, OrdersClient
18+
from .clients import DataClient, OrdersClient # NOQA
1919

20-
__all__ = [Session, OrdersClient, order_request, reporting, Auth, DataClient]
20+
__all__ = [
21+
'Auth',
22+
'DataClient'
23+
'OrdersClient',
24+
'order_request',
25+
'reporting',
26+
'Session',
27+
]

planet/auth.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@
3030
BASE_URL = f'{PLANET_BASE_URL}/v0/auth'
3131
ENV_API_KEY = 'PL_API_KEY'
3232

33+
AuthType = httpx.Auth
34+
3335

3436
class Auth(metaclass=abc.ABCMeta):
3537
'''Handle authentication information for use with Planet APIs.'''
3638

3739
@staticmethod
38-
def from_key(key: str) -> Auth:
40+
def from_key(key: str) -> AuthType:
3941
'''Obtain authentication from api key.
4042
4143
Parameters:
@@ -46,7 +48,7 @@ def from_key(key: str) -> Auth:
4648
return auth
4749

4850
@staticmethod
49-
def from_file(filename: str = None) -> Auth:
51+
def from_file(filename: str = None) -> AuthType:
5052
'''Create authentication from secret file.
5153
5254
The secret file is named `.planet.json` and is stored in the user
@@ -71,7 +73,7 @@ def from_file(filename: str = None) -> Auth:
7173
return auth
7274

7375
@staticmethod
74-
def from_env(variable_name: str = None) -> Auth:
76+
def from_env(variable_name: str = None) -> AuthType:
7577
'''Create authentication from environment variable.
7678
7779
Reads the `PL_API_KEY` environment variable
@@ -80,7 +82,7 @@ def from_env(variable_name: str = None) -> Auth:
8082
variable_name: Alternate environment variable.
8183
'''
8284
variable_name = variable_name or ENV_API_KEY
83-
api_key = os.getenv(variable_name)
85+
api_key = os.getenv(variable_name, '')
8486
try:
8587
auth = APIKeyAuth(api_key)
8688
LOGGER.debug(f'Auth set from environment variable {variable_name}')
@@ -91,7 +93,9 @@ def from_env(variable_name: str = None) -> Auth:
9193
return auth
9294

9395
@staticmethod
94-
def from_login(email: str, password: str, base_url: str = None) -> Auth:
96+
def from_login(email: str,
97+
password: str,
98+
base_url: str = None) -> AuthType:
9599
'''Create authentication from login email and password.
96100
97101
Note: To keep your password secure, the use of `getpass` is
@@ -113,14 +117,18 @@ def from_login(email: str, password: str, base_url: str = None) -> Auth:
113117

114118
@classmethod
115119
@abc.abstractmethod
116-
def from_dict(cls, data: dict) -> Auth:
120+
def from_dict(cls, data: dict) -> AuthType:
117121
pass
118122

119123
@property
120124
@abc.abstractmethod
121125
def value(self):
122126
pass
123127

128+
@abc.abstractmethod
129+
def to_dict(self) -> dict:
130+
pass
131+
124132
def write(self, filename: str = None):
125133
'''Write authentication information.
126134

planet/clients/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
from .orders import OrdersClient
1616

1717
__all__ = [
18-
DataClient,
19-
OrdersClient,
18+
'DataClient',
19+
'OrdersClient',
2020
]

planet/clients/data.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,11 @@ async def create_search(self,
175175

176176
# TODO: validate item_types
177177
request_json = {
178-
'name': name, 'filter': search_filter, 'item_types': item_types
178+
'name': name,
179+
'filter': search_filter,
180+
'item_types': item_types,
181+
'__daily_email_enabled': enable_email
179182
}
180-
if enable_email:
181-
request_json['__daily_email_enabled'] = True
182183

183184
request = self._request(url, method='POST', json=request_json)
184185
response = await self._do_request(request)

planet/http.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import httpx
2121

22-
from .auth import Auth
22+
from .auth import Auth, AuthType
2323
from . import exceptions, models
2424
from .__version__ import __version__
2525

@@ -112,7 +112,7 @@ class Session(BaseSession):
112112
```
113113
'''
114114

115-
def __init__(self, auth: Auth = None):
115+
def __init__(self, auth: AuthType = None):
116116
"""Initialize a Session.
117117
118118
Parameters:

planet/order_request.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"""Functionality for preparing order details for use in creating an order"""
1515
from __future__ import annotations # https://stackoverflow.com/a/33533514
1616
import logging
17-
from typing import List
17+
from typing import Any, Dict, List
1818

1919
from . import geojson, specs
2020

@@ -67,7 +67,7 @@ def build_request(name: str,
6767
planet.specs.SpecificationException: If order_type is not a valid
6868
order type.
6969
'''
70-
details = {'name': name, 'products': products}
70+
details: Dict[str, Any] = {'name': name, 'products': products}
7171

7272
if subscription_id:
7373
details['subscription_id'] = subscription_id
@@ -79,8 +79,8 @@ def build_request(name: str,
7979
details['notifications'] = notifications
8080

8181
if order_type:
82-
order_type = specs.validate_order_type(order_type)
83-
details['order_type'] = order_type
82+
validated_order_type = specs.validate_order_type(order_type)
83+
details['order_type'] = validated_order_type
8484

8585
if tools:
8686
details['tools'] = tools
@@ -108,18 +108,19 @@ def product(item_ids: List[str],
108108
are not valid bundles or if item_type is not valid for the given
109109
bundle or fallback bundle.
110110
'''
111-
product_bundle = specs.validate_bundle(product_bundle)
112-
item_type = specs.validate_item_type(item_type, product_bundle)
111+
validated_product_bundle = specs.validate_bundle(product_bundle)
112+
item_type = specs.validate_item_type(item_type, validated_product_bundle)
113113

114114
if fallback_bundle is not None:
115-
fallback_bundle = specs.validate_bundle(fallback_bundle)
116-
specs.validate_item_type(item_type, fallback_bundle)
117-
product_bundle = ','.join([product_bundle, fallback_bundle])
115+
validated_fallback_bundle = specs.validate_bundle(fallback_bundle)
116+
specs.validate_item_type(item_type, validated_fallback_bundle)
117+
validated_product_bundle = ','.join(
118+
[validated_product_bundle, validated_fallback_bundle])
118119

119120
product_dict = {
120121
'item_ids': item_ids,
121122
'item_type': item_type,
122-
'product_bundle': product_bundle
123+
'product_bundle': validated_product_bundle
123124
}
124125
return product_dict
125126

planet/reporting.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,19 @@ def update_state(self, state: str):
9090
def update(self, state: str = None, order_id: str = None):
9191
if state:
9292
self.state = state
93-
try:
94-
self.bar.postfix[1] = self.state
95-
except AttributeError:
96-
# If the bar is disabled, attempting to access self.bar.postfix
97-
# will result in an error. In this case, just skip it.
98-
pass
93+
if self.bar is not None:
94+
try:
95+
self.bar.postfix[1] = self.state
96+
except AttributeError:
97+
# If the bar is disabled, attempting to access
98+
# self.bar.postfix will result in an error. In this
99+
# case, just skip it.
100+
pass
99101

100102
if order_id:
101103
self.order_id = order_id
102-
self.bar.set_description_str(self.desc, refresh=False)
104+
if self.bar is not None:
105+
self.bar.set_description_str(self.desc, refresh=False)
103106

104-
self.bar.refresh()
107+
if self.bar is not None:
108+
self.bar.refresh()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
'pytest', 'pytest-asyncio==0.16', 'pytest-cov', 'respx==0.16.3'
3535
]
3636

37-
lint_requires = ['flake8', 'yapf']
37+
lint_requires = ['flake8', 'mypy', 'yapf']
3838

3939
doc_requires = [
4040
'mkdocs==1.3',

tests/integration/test_data_api.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,10 @@ async def test_create_search_basic(search_filter, session):
174174

175175
# check that request is correct
176176
expected_request = {
177-
"item_types": ["PSScene"], "filter": search_filter, "name": "test"
177+
"item_types": ["PSScene"],
178+
"filter": search_filter,
179+
"name": "test",
180+
"__daily_email_enabled": False
178181
}
179182
actual_body = json.loads(respx.calls[0].request.content)
180183
assert actual_body == expected_request

0 commit comments

Comments
 (0)