cecil 0.0.16__py3-none-any.whl → 0.0.17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cecil might be problematic. Click here for more details.

cecil/client.py CHANGED
@@ -1,40 +1,42 @@
1
1
  import os
2
+ from typing import Dict, List
3
+
4
+ import pandas as pd
2
5
  import requests
3
6
  import snowflake.connector
4
-
5
7
  from pydantic import BaseModel
6
8
  from requests import auth
7
- from typing import Dict, List
8
9
 
9
10
  from .errors import (
10
11
  Error,
11
12
  _handle_bad_request,
12
13
  _handle_not_found,
14
+ _handle_too_many_requests,
13
15
  _handle_unprocessable_entity,
14
16
  )
15
-
16
17
  from .models import (
17
18
  AOI,
18
19
  AOICreate,
19
20
  DataRequest,
20
21
  DataRequestCreate,
21
- Transformation,
22
- TransformationCreate,
22
+ OrganisationCreate,
23
23
  RecoverAPIKey,
24
24
  RecoverAPIKeyRequest,
25
25
  RotateAPIKey,
26
26
  RotateAPIKeyRequest,
27
+ SignUpRequest,
28
+ SignUpResponse,
27
29
  SnowflakeCredentials,
30
+ Transformation,
31
+ TransformationCreate,
32
+ User,
33
+ UserCreate,
28
34
  )
29
-
30
35
  from .version import __version__
31
36
 
32
- # TODO: Documentation (Google style)
33
- # TODO: Add HTTP retries
34
-
35
37
 
36
38
  class Client:
37
- def __init__(self, env=None):
39
+ def __init__(self, env: str = None) -> None:
38
40
  self._api_auth = None
39
41
  self._base_url = (
40
42
  "https://api.cecil.earth" if env is None else f"https://{env}.cecil.earth"
@@ -65,14 +67,13 @@ class Client:
65
67
  res = self._get(url=f"/v0/data-requests/{id}")
66
68
  return DataRequest(**res)
67
69
 
68
- def list_data_requests(self):
70
+ def list_data_requests(self) -> List[DataRequest]:
69
71
  res = self._get(url="/v0/data-requests")
70
72
  return [DataRequest(**record) for record in res["records"]]
71
73
 
72
74
  def create_transformation(
73
75
  self, data_request_id: str, crs: str, spatial_resolution: float
74
76
  ) -> Transformation:
75
- # TODO: check if data request is completed before creating transformation
76
77
  res = self._post(
77
78
  url="/v0/transformations",
78
79
  model=TransformationCreate(
@@ -91,7 +92,7 @@ class Client:
91
92
  res = self._get(url="/v0/transformations")
92
93
  return [Transformation(**record) for record in res["records"]]
93
94
 
94
- def query(self, sql):
95
+ def query(self, sql: str) -> pd.DataFrame:
95
96
  if self._snowflake_creds is None:
96
97
  res = self._get(url="/v0/data-access-credentials")
97
98
  self._snowflake_creds = SnowflakeCredentials(**res)
@@ -108,7 +109,7 @@ class Client:
108
109
 
109
110
  def recover_api_key(self, email: str) -> RecoverAPIKey:
110
111
  res = self._post(
111
- url=f"/v0/recover-api-key",
112
+ url="/v0/api-key/recover",
112
113
  model=RecoverAPIKeyRequest(email=email),
113
114
  skip_auth=True,
114
115
  )
@@ -116,10 +117,43 @@ class Client:
116
117
  return RecoverAPIKey(**res)
117
118
 
118
119
  def rotate_api_key(self) -> RotateAPIKey:
119
- res = self._post(url=f"/v0/rotate-api-key", model=RotateAPIKeyRequest())
120
+ res = self._post(url=f"/v0/api-key/rotate", model=RotateAPIKeyRequest())
120
121
 
121
122
  return RotateAPIKey(**res)
122
123
 
124
+ def sign_up(
125
+ self, organisation: Dict[str, str], user: Dict[str, str]
126
+ ) -> SignUpResponse:
127
+ res = self._post(
128
+ url="/v0/sign-up",
129
+ model=SignUpRequest(
130
+ organisation=OrganisationCreate(**organisation),
131
+ user=UserCreate(**user),
132
+ ),
133
+ skip_auth=True,
134
+ )
135
+
136
+ return SignUpResponse(**res)
137
+
138
+ def create_user(self, first_name: str, last_name: str, email: str) -> User:
139
+ res = self._post(
140
+ url="/v0/users",
141
+ model=UserCreate(
142
+ first_name=first_name,
143
+ last_name=last_name,
144
+ email=email,
145
+ ),
146
+ )
147
+ return User(**res)
148
+
149
+ def get_user(self, id: str) -> User:
150
+ res = self._get(url=f"/v0/users/{id}")
151
+ return User(**res)
152
+
153
+ def list_users(self) -> List[User]:
154
+ res = self._get(url="/v0/users")
155
+ return [User(**record) for record in res["records"]]
156
+
123
157
  def _request(self, method: str, url: str, skip_auth=False, **kwargs) -> Dict:
124
158
 
125
159
  if skip_auth is False:
@@ -141,7 +175,12 @@ class Client:
141
175
 
142
176
  except requests.exceptions.ConnectionError:
143
177
  raise Error("failed to connect to the Cecil Platform")
178
+
144
179
  except requests.exceptions.HTTPError as err:
180
+ message = f"Request failed with status code {err.response.status_code}"
181
+ if err.response.text != "":
182
+ message += f": {err.response.text}"
183
+
145
184
  match err.response.status_code:
146
185
  case 400:
147
186
  _handle_bad_request(err.response)
@@ -151,6 +190,8 @@ class Client:
151
190
  _handle_not_found(err.response)
152
191
  case 422:
153
192
  _handle_unprocessable_entity(err.response)
193
+ case 429:
194
+ _handle_too_many_requests(err.response)
154
195
  case 500:
155
196
  raise Error("internal server error")
156
197
  case _:
cecil/errors.py CHANGED
@@ -47,6 +47,18 @@ def _handle_not_found(response):
47
47
  raise Error("resource not found", details)
48
48
 
49
49
 
50
+ def _handle_too_many_requests(response):
51
+ if not _is_json(response.text):
52
+ raise Error("too many requests")
53
+
54
+ details = {}
55
+
56
+ for key, value in response.json().items():
57
+ details[_format_json_key(key)] = value
58
+
59
+ raise Error("too many requests", details)
60
+
61
+
50
62
  def _handle_unprocessable_entity(response):
51
63
  if not _is_json(response.text):
52
64
  raise Error(f"failed to process request")
cecil/models.py CHANGED
@@ -36,6 +36,11 @@ class DataRequestCreate(BaseModel):
36
36
  dataset_id: str
37
37
 
38
38
 
39
+ class OrganisationCreate(BaseModel):
40
+ model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
41
+ name: str
42
+
43
+
39
44
  class RecoverAPIKey(BaseModel):
40
45
  model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
41
46
  message: str
@@ -77,3 +82,31 @@ class SnowflakeCredentials(BaseModel):
77
82
  account: SecretStr
78
83
  user: SecretStr
79
84
  password: SecretStr
85
+
86
+
87
+ class User(BaseModel):
88
+ model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
89
+ id: str
90
+ first_name: str
91
+ last_name: str
92
+ email: str
93
+ created_at: datetime.datetime
94
+ created_by: str
95
+
96
+
97
+ class UserCreate(BaseModel):
98
+ model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
99
+ first_name: str
100
+ last_name: str
101
+ email: str
102
+
103
+
104
+ class SignUpRequest(BaseModel):
105
+ model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
106
+ organisation: OrganisationCreate
107
+ user: UserCreate
108
+
109
+
110
+ class SignUpResponse(BaseModel):
111
+ model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
112
+ message: str
cecil/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.0.16"
1
+ __version__ = "0.0.17"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cecil
3
- Version: 0.0.16
3
+ Version: 0.0.17
4
4
  Summary: Python SDK for Cecil Earth
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE.txt
@@ -0,0 +1,9 @@
1
+ cecil/__init__.py,sha256=AEcRl73BDSAQe6W0d1PDD87IEcumARtREl7dCVa_YQY,86
2
+ cecil/client.py,sha256=n8Ft-K1XLt430RCM6jUgBwWhwQlCJT8umyZp6RKpIyw,7054
3
+ cecil/errors.py,sha256=ZNiSTYH2MgNZ7tNIgV07-Ge3KtmdncfzWiBi9yjURGs,1818
4
+ cecil/models.py,sha256=0n5q7oUA7khdc5eB6C8aSW6Yx5LgyN_fA-GHb8y9Z7M,2834
5
+ cecil/version.py,sha256=WlMBNrzKywm5RAbqEVgEgcG7Opc4cf3-wpAnO8PdoEI,23
6
+ cecil-0.0.17.dist-info/METADATA,sha256=pK-PX-p6uyf-_MNbICW_ukGHnKzdnHiSFz5pFW3dOLw,2659
7
+ cecil-0.0.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ cecil-0.0.17.dist-info/licenses/LICENSE.txt,sha256=mUexcmfYx3bG1VIzAdQTOf_NzStYw6-QkKVdUY_d4i4,1066
9
+ cecil-0.0.17.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- cecil/__init__.py,sha256=AEcRl73BDSAQe6W0d1PDD87IEcumARtREl7dCVa_YQY,86
2
- cecil/client.py,sha256=hykvGQrpuAEQR_TawLKCwc_mWsjD72uxAZHaOTZjf1M,5764
3
- cecil/errors.py,sha256=r9NNRtv_oO_hblnh-VOlAf767cJqmlnbJfHB63OA_zY,1538
4
- cecil/models.py,sha256=xkjrLAOenJboRtzRPihT-C8jpadngePz4KzLNJoemHM,2012
5
- cecil/version.py,sha256=8ss7zPyQ3YfaQJw9IIGX35NOL7ASZ7-LErAxKnQDN7c,23
6
- cecil-0.0.16.dist-info/METADATA,sha256=7f2D9tc10goXMoeFgZqjHWeENrVyUq6H0OXmma75eWY,2659
7
- cecil-0.0.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
- cecil-0.0.16.dist-info/licenses/LICENSE.txt,sha256=mUexcmfYx3bG1VIzAdQTOf_NzStYw6-QkKVdUY_d4i4,1066
9
- cecil-0.0.16.dist-info/RECORD,,
File without changes