Skip to content

Commit dc6783f

Browse files
committed
Merge branch 'experiment/typings' into develop.
2 parents e371267 + 179033f commit dc6783f

File tree

5 files changed

+46
-42
lines changed

5 files changed

+46
-42
lines changed

NOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Ideas
2+
3+
- use something like [colander](https://docs.pylonsproject.org/projects/colander/en/latest/basics.html) to deserialize JSON into Python classes (and potentially validate it, too)
4+
- how about _async_?

src/autodesk_forge_sdk/auth.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class AuthenticationClient(BaseClient):
4848
**Documentation**: https://forge.autodesk.com/en/docs/oauth/v2/reference/http
4949
"""
5050

51-
def __init__(self, base_url=BASE_URL):
51+
def __init__(self, base_url: str=BASE_URL):
5252
"""
5353
Create new instance of the client.
5454
@@ -57,7 +57,7 @@ def __init__(self, base_url=BASE_URL):
5757
"""
5858
BaseClient.__init__(self, base_url)
5959

60-
def authenticate(self, client_id, client_secret, scopes):
60+
def authenticate(self, client_id: str, client_secret: str, scopes: list[Scope]) -> dict:
6161
"""
6262
Generate a two-legged access token for specific set of scopes.
6363
@@ -88,7 +88,7 @@ def authenticate(self, client_id, client_secret, scopes):
8888
}
8989
return self._post('/authenticate', form=form).json()
9090

91-
def get_authorization_url(self, client_id, response_type, redirect_uri, scopes, state=None):
91+
def get_authorization_url(self, client_id: str, response_type: str, redirect_uri: str, scopes: list[Scope], state: str=None) -> str:
9292
"""
9393
Generate a URL to redirect an end user to in order to acquire the user’s consent
9494
for your app to access the specified resources.
@@ -122,7 +122,7 @@ def get_authorization_url(self, client_id, response_type, redirect_uri, scopes,
122122
url += '&state={}'.format(quote(state))
123123
return url
124124

125-
def get_token(self, client_id, client_secret, code, redirect_uri):
125+
def get_token(self, client_id: str, client_secret: str, code: str, redirect_uri: str) -> dict:
126126
"""
127127
Exchange an authorization code extracted from `get_authorization_url` callback for a three-legged access token.
128128
This API will only be used when the 'Authorization Code' grant type is being adopted.
@@ -159,7 +159,7 @@ def get_token(self, client_id, client_secret, code, redirect_uri):
159159
}
160160
return self._post('/gettoken', form=form).json()
161161

162-
def refresh_token(self, client_id, client_secret, refresh_token, scopes):
162+
def refresh_token(self, client_id: str, client_secret: str, refresh_token: str, scopes: list[Scope]) -> dict:
163163
"""
164164
Acquire a new access token by using the refresh token provided by `get_token`.
165165
@@ -193,7 +193,7 @@ def refresh_token(self, client_id, client_secret, refresh_token, scopes):
193193
}
194194
return self._post('/refreshtoken', form=form).json()
195195

196-
def get_user_profile(self, access_token):
196+
def get_user_profile(self, access_token: str) -> dict:
197197
"""
198198
Get the profile information of an authorizing end user in a three-legged context.
199199
@@ -217,7 +217,7 @@ def get_user_profile(self, access_token):
217217
return self._get('/users/@me', headers=headers).json()
218218

219219
class TokenProviderInterface:
220-
def get_token(self, scopes):
220+
def get_token(self, scopes: list[Scope]) -> str:
221221
"""
222222
Generates access token for given set of scopes.
223223
@@ -235,7 +235,7 @@ class SimpleTokenProvider(TokenProviderInterface):
235235
When using this approach, make sure that the hard-coded access token supports all the scopes that may be needed.
236236
"""
237237

238-
def __init__(self, access_token):
238+
def __init__(self, access_token: str):
239239
"""
240240
Create new instance of the provider.
241241
@@ -244,15 +244,15 @@ def __init__(self, access_token):
244244
"""
245245
self.access_token = access_token
246246

247-
def get_token(self, scopes):
247+
def get_token(self, scopes: list[Scope]) -> str:
248248
return self.access_token
249249

250250
class OAuthTokenProvider(TokenProviderInterface):
251251
"""
252252
Helper class that automatically generates (and caches) access tokens using specific app credentials.
253253
"""
254254

255-
def __init__(self, client_id, client_secret):
255+
def __init__(self, client_id: str, client_secret: str):
256256
"""
257257
Create new instance of the provider.
258258
@@ -265,7 +265,7 @@ def __init__(self, client_id, client_secret):
265265
self.auth_client = AuthenticationClient()
266266
self.cache = {}
267267

268-
def get_token(self, scopes):
268+
def get_token(self, scopes: list[Scope]) -> str:
269269
cache_key = '+'.join(map(lambda s: s.value, scopes))
270270
now = datetime.now()
271271
if cache_key in self.cache:
@@ -277,7 +277,7 @@ def get_token(self, scopes):
277277
return auth
278278

279279
class BaseOAuthClient(BaseClient):
280-
def __init__(self, token_provider, base_url):
280+
def __init__(self, token_provider: TokenProviderInterface, base_url: str):
281281
"""
282282
Create new instance of the client.
283283
@@ -288,31 +288,31 @@ def __init__(self, token_provider, base_url):
288288
BaseClient.__init__(self, base_url)
289289
self.token_provider = token_provider
290290

291-
def _get(self, url, scopes, params=None, headers=None):
291+
def _get(self, url: str, scopes: list[Scope], params: dict=None, headers: dict=None):
292292
if not headers:
293293
headers = {}
294294
self._set_auth_headers(headers, scopes)
295295
return BaseClient._get(self, url, params, headers)
296296

297-
def _post(self, url, scopes, form=None, json=None, buff=None, params=None, headers=None):
297+
def _post(self, url: str, scopes: list[Scope], form: dict=None, json: dict=None, buff=None, params: dict=None, headers: dict=None):
298298
if not headers:
299299
headers = {}
300300
self._set_auth_headers(headers, scopes)
301301
return BaseClient._post(self, url, form, json, buff, params, headers)
302302

303-
def _put(self, url, scopes, form=None, json=None, buff=None, params=None, headers=None):
303+
def _put(self, url: str, scopes: list[Scope], form: dict=None, json: dict=None, buff=None, params: dict=None, headers: dict=None):
304304
if not headers:
305305
headers = {}
306306
self._set_auth_headers(headers, scopes)
307307
return BaseClient._put(self, url, form, json, buff, params, headers)
308308

309-
def _delete(self, url, scopes, params=None, headers=None):
309+
def _delete(self, url: str, scopes: list[Scope], params: dict=None, headers: dict=None):
310310
if not headers:
311311
headers = {}
312312
self._set_auth_headers(headers, scopes)
313313
return BaseClient._delete(self, url, params, headers)
314314

315-
def _set_auth_headers(self, headers, scopes):
315+
def _set_auth_headers(self, headers: dict, scopes: list[Scope]):
316316
if not 'Authorization' in headers:
317317
auth = self.token_provider.get_token(scopes)
318318
headers['Authorization'] = 'Bearer {}'.format(auth['access_token'])

src/autodesk_forge_sdk/base.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import requests
22

33
class BaseClient(object):
4-
def __init__(self, base_url):
4+
def __init__(self, base_url: str):
55
self.base_url = base_url
66

7-
def _resolve_url(self, url):
7+
def _resolve_url(self, url: str) -> str:
88
if url.startswith('/'):
99
url = self.base_url + url
1010
return url
1111

12-
def _get(self, url, params=None, headers=None):
12+
def _get(self, url: str, params: dict=None, headers: dict=None) -> requests.Response:
1313
url = self._resolve_url(url)
1414
response = requests.get(url, params=params, headers=headers)
1515
response.raise_for_status()
1616
return response
1717

18-
def _post(self, url, form=None, json=None, buff=None, params=None, headers=None):
18+
def _post(self, url: str, form: dict=None, json: dict=None, buff=None, params: dict=None, headers: dict=None) -> requests.Response:
1919
url = self._resolve_url(url)
2020
response = None
2121
if form:
@@ -29,7 +29,7 @@ def _post(self, url, form=None, json=None, buff=None, params=None, headers=None)
2929
response.raise_for_status()
3030
return response
3131

32-
def _put(self, url, form=None, json=None, buff=None, params=None, headers=None):
32+
def _put(self, url: str, form: dict=None, json: dict=None, buff=None, params: dict=None, headers: dict=None) -> requests.Response:
3333
url = self._resolve_url(url)
3434
response = None
3535
if form:
@@ -43,7 +43,7 @@ def _put(self, url, form=None, json=None, buff=None, params=None, headers=None):
4343
response.raise_for_status()
4444
return response
4545

46-
def _delete(self, url, params=None, headers=None):
46+
def _delete(self, url: str, params: dict=None, headers: dict=None) -> requests.Response:
4747
url = self._resolve_url(url)
4848
response = requests.delete(url, params=params, headers=headers)
4949
response.raise_for_status()

src/autodesk_forge_sdk/md.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class ModelDerivativeClient(BaseOAuthClient):
3333
**Documentation**: https://forge.autodesk.com/en/docs/model-derivative/v2/reference/http
3434
"""
3535

36-
def __init__(self, token_provider, base_url=BASE_URL):
36+
def __init__(self, token_provider: TokenProviderInterface(), base_url: str = BASE_URL):
3737
"""
3838
Create new instance of the client.
3939
@@ -62,7 +62,7 @@ def get_token(self, scopes):
6262
"""
6363
BaseOAuthClient.__init__(self, token_provider, base_url)
6464

65-
def get_formats(self):
65+
def get_formats(self) -> dict:
6666
"""
6767
Return an up-to-date list of Forge-supported translations, that you can use to identify
6868
which types of derivatives are supported for each source file type.
@@ -77,13 +77,13 @@ def get_formats(self):
7777
FORGE_CLIENT_ID = os.environ["FORGE_CLIENT_ID"]
7878
FORGE_CLIENT_SECRET = os.environ["FORGE_CLIENT_SECRET"]
7979
client = ModelDerivativeClient(OAuthTokenProvider(FORGE_CLIENT_ID, FORGE_CLIENT_SECRET))
80-
formats = client.get_formats()
81-
print(formats)
80+
resp = client.get_formats()
81+
print(resp.formats)
8282
```
8383
"""
8484
return self._get('/designdata/formats', []).json()
8585

86-
def submit_job(self, urn, output_formats, output_region, root_filename=None, workflow_id=None, workflow_attr=None, force=False):
86+
def submit_job(self, urn: str, output_formats: list[dict], output_region: str, root_filename: str=None, workflow_id: str=None, workflow_attr: str=None, force: bool = False) -> dict:
8787
"""
8888
Translate a design from one format to another format.
8989

src/autodesk_forge_sdk/oss.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class OSSClient(BaseOAuthClient):
3939
**Documentation**: https://forge.autodesk.com/en/docs/data/v2/reference/http
4040
"""
4141

42-
def __init__(self, token_provider, base_url=BASE_URL):
42+
def __init__(self, token_provider: TokenProviderInterface(), base_url: str = BASE_URL):
4343
"""
4444
Create new instance of the client.
4545
@@ -68,7 +68,7 @@ def get_token(self, scopes):
6868
"""
6969
BaseOAuthClient.__init__(self, token_provider, base_url)
7070

71-
def _get_paginated(self, url, scopes, params=None, headers=None):
71+
def _get_paginated(self, url: str, scopes: list[Scope], params: dict=None, headers: dict=None) -> list:
7272
items = []
7373
while url:
7474
json = self._get(url, scopes, params, headers).json()
@@ -79,7 +79,7 @@ def _get_paginated(self, url, scopes, params=None, headers=None):
7979
url = None
8080
return items
8181

82-
def get_buckets(self, region=None, limit=None, start_at=None):
82+
def get_buckets(self, region: str=None, limit: int=None, start_at: str=None) -> dict:
8383
"""
8484
List buckets owned by the application, using pagination.
8585
@@ -112,7 +112,7 @@ def get_buckets(self, region=None, limit=None, start_at=None):
112112
params['startAt'] = start_at
113113
return self._get('/buckets', READ_SCOPES, params).json()
114114

115-
def get_all_buckets(self, region=None):
115+
def get_all_buckets(self, region: str=None) -> list:
116116
"""
117117
List all buckets owned by the application. Similar to `OSSClient.get_buckets` but returning all results without pagination.
118118
@@ -138,7 +138,7 @@ def get_all_buckets(self, region=None):
138138
params['region'] = region
139139
return self._get_paginated('/buckets', READ_SCOPES, params)
140140

141-
def get_bucket_details(self, bucket_key):
141+
def get_bucket_details(self, bucket_key: str) -> dict:
142142
"""
143143
Get bucket details in JSON format if the caller is the owner of the bucket.
144144
A request by any other application will result in a response of 403 Forbidden.
@@ -160,7 +160,7 @@ def get_bucket_details(self, bucket_key):
160160
"""
161161
return self._get('/buckets/{}/details'.format(quote(bucket_key)), READ_SCOPES).json()
162162

163-
def create_bucket(self, bucket_key, data_retention_policy, region):
163+
def create_bucket(self, bucket_key: str, data_retention_policy: DataRetention, region: str) -> dict:
164164
"""
165165
Create a bucket. Buckets are arbitrary spaces that are created by applications
166166
and are used to store objects for later retrieval. A bucket is owned by the application
@@ -197,7 +197,7 @@ def create_bucket(self, bucket_key, data_retention_policy, region):
197197
}
198198
return self._post('/buckets', WRITE_SCOPES, json=json, headers=headers).json()
199199

200-
def delete_bucket(self, bucket_key):
200+
def delete_bucket(self, bucket_key: str):
201201
"""
202202
Delete a bucket. The bucket must be owned by the application.
203203
@@ -206,9 +206,9 @@ def delete_bucket(self, bucket_key):
206206
Args:
207207
bucket_key (str): Name of the bucket to be deleted.
208208
"""
209-
return self._delete('/buckets/{}'.format(quote(bucket_key)), DELETE_SCOPES)
209+
self._delete('/buckets/{}'.format(quote(bucket_key)), DELETE_SCOPES)
210210

211-
def get_objects(self, bucket_key, limit=None, begins_with=None, start_at=None):
211+
def get_objects(self, bucket_key: str, limit: int=None, begins_with: str=None, start_at: str=None) -> dict:
212212
"""
213213
List objects in bucket, using pagination. It is only available to the bucket creator.
214214
@@ -243,7 +243,7 @@ def get_objects(self, bucket_key, limit=None, begins_with=None, start_at=None):
243243
params['startAt'] = start_at
244244
return self._get('/buckets/{}/objects'.format(quote(bucket_key)), READ_SCOPES, params).json()
245245

246-
def get_all_objects(self, bucket_key, begins_with=None):
246+
def get_all_objects(self, bucket_key: str, begins_with: str=None) -> list:
247247
"""
248248
List all objects in bucket. Similar to `OSSClient.get_objects` but returning all results without pagination.
249249
@@ -268,7 +268,7 @@ def get_all_objects(self, bucket_key, begins_with=None):
268268
params['beginsWith'] = begins_with
269269
return self._get_paginated('/buckets/{}/objects'.format(quote(bucket_key)), READ_SCOPES, params)
270270

271-
def get_object_details(self, bucket_key, object_key):
271+
def get_object_details(self, bucket_key: str, object_key: str) -> dict:
272272
"""
273273
Get object details in JSON format.
274274
@@ -294,7 +294,7 @@ def get_object_details(self, bucket_key, object_key):
294294
url = '/buckets/{}/objects/{}'.format(quote(bucket_key), quote(object_key))
295295
return self._get(url, READ_SCOPES).json()
296296

297-
def upload_object(self, bucket_key, object_key, buff):
297+
def upload_object(self, bucket_key: str, object_key: str, buff) -> list:
298298
"""
299299
Upload an object. If the specified object name already exists in the bucket,
300300
the uploaded content will overwrite the existing content for the bucket name/object name combination.
@@ -326,7 +326,7 @@ def upload_object(self, bucket_key, object_key, buff):
326326
url = '/buckets/{}/objects/{}'.format(quote(bucket_key), quote(object_key))
327327
return self._put(url, WRITE_SCOPES, buff=buff).json()
328328

329-
def delete_object(self, bucket_key, object_key):
329+
def delete_object(self, bucket_key: str, object_key: str):
330330
"""
331331
Delete an object from bucket.
332332
@@ -337,4 +337,4 @@ def delete_object(self, bucket_key, object_key):
337337
object_key (str): Name of the object to be removed.
338338
"""
339339
url = '/buckets/{}/objects/{}'.format(quote(bucket_key), quote(object_key))
340-
return self._delete(url, DELETE_SCOPES)
340+
self._delete(url, DELETE_SCOPES)

0 commit comments

Comments
 (0)