cecil 0.0.7__tar.gz
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-0.0.7/.gitignore +6 -0
- cecil-0.0.7/CONTRIBUTING.md +21 -0
- cecil-0.0.7/LICENSE.txt +21 -0
- cecil-0.0.7/Makefile +33 -0
- cecil-0.0.7/PKG-INFO +119 -0
- cecil-0.0.7/README.md +103 -0
- cecil-0.0.7/__about__.py +1 -0
- cecil-0.0.7/pyproject.toml +30 -0
- cecil-0.0.7/src/cecil/__init__.py +1 -0
- cecil-0.0.7/src/cecil/client.py +131 -0
- cecil-0.0.7/src/cecil/models.py +80 -0
- cecil-0.0.7/tests/__init__.py +0 -0
- cecil-0.0.7/tests/test_client.py +90 -0
cecil-0.0.7/.gitignore
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Development installation
|
|
2
|
+
|
|
3
|
+
Install packaging/distribution tools:
|
|
4
|
+
|
|
5
|
+
```shell
|
|
6
|
+
pip install hatch twine
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Install linter
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
pip install black
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
From top-level repo directory, install the package in editable mode:
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Local edits to the package will immediately take effect.
|
cecil-0.0.7/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 cecilearth
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cecil-0.0.7/Makefile
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
HL = @printf "\033[36m>> $1\033[0m\n"
|
|
2
|
+
|
|
3
|
+
default: help
|
|
4
|
+
|
|
5
|
+
.PHONY: help
|
|
6
|
+
help:
|
|
7
|
+
@echo "Usage: make <target>\n"
|
|
8
|
+
@grep -E ".+:\s.*?##" $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?##"}; {printf "\033[36m%-24s\033[0m %s\n", $$1, $$2}'
|
|
9
|
+
|
|
10
|
+
.PHONY: build
|
|
11
|
+
build: clean test ## Build package
|
|
12
|
+
$(call HL,build)
|
|
13
|
+
hatch build
|
|
14
|
+
|
|
15
|
+
.PHONY: clean
|
|
16
|
+
clean: ## Clean dist
|
|
17
|
+
$(call HL,clean)
|
|
18
|
+
hatch clean
|
|
19
|
+
|
|
20
|
+
.PHONY: publish-test
|
|
21
|
+
publish-test: build ## Publish package to testpypi
|
|
22
|
+
$(call HL,publish-test)
|
|
23
|
+
twine upload --repository testpypi dist/*
|
|
24
|
+
|
|
25
|
+
.PHONY: publish-prod
|
|
26
|
+
publish-prod: build ## Publish package to pypi
|
|
27
|
+
$(call HL,publish-prod)
|
|
28
|
+
twine upload --repository pypi dist/*
|
|
29
|
+
|
|
30
|
+
.PHONY: test
|
|
31
|
+
test: ## Run tests
|
|
32
|
+
$(call HL,test)
|
|
33
|
+
hatch test -v
|
cecil-0.0.7/PKG-INFO
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: cecil
|
|
3
|
+
Version: 0.0.7
|
|
4
|
+
Summary: Python SDK for Cecil Earth
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE.txt
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Requires-Dist: pydantic
|
|
13
|
+
Requires-Dist: requests
|
|
14
|
+
Requires-Dist: snowflake-connector-python[pandas]
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# Cecil SDK
|
|
18
|
+
|
|
19
|
+
[](https://pypi.org/project/cecil-sdk)
|
|
20
|
+
[](https://pypi.org/project/cecil-sdk)
|
|
21
|
+
|
|
22
|
+
-----
|
|
23
|
+
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
- [Installation](#installation)
|
|
27
|
+
- [Authentication](#authentication)
|
|
28
|
+
- [License](#license)
|
|
29
|
+
- [Examples](#examples)
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```shell
|
|
34
|
+
pip install cecil
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Authentication
|
|
38
|
+
|
|
39
|
+
Set `CECIL_API_KEY` environment variable to your Cecil API key.
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
### Create an AOI and data request using the Cecil client
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import cecil
|
|
47
|
+
|
|
48
|
+
client = cecil.Client()
|
|
49
|
+
|
|
50
|
+
my_aoi = client.create_aoi(
|
|
51
|
+
name="My AOI",
|
|
52
|
+
geometry={
|
|
53
|
+
"type": "Polygon",
|
|
54
|
+
"coordinates": [
|
|
55
|
+
[
|
|
56
|
+
[145.410408835, -42.004083838],
|
|
57
|
+
[145.410408835, -42.004203978],
|
|
58
|
+
[145.410623191, -42.004203978],
|
|
59
|
+
[145.410623191, -42.004083838],
|
|
60
|
+
[145.410408835, -42.004083838],
|
|
61
|
+
]
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Get dataset ID from docs.cecil.earth -> Datasets
|
|
67
|
+
planet_forest_carbon_diligence_id = "c2dd4f55-56f6-4d05-aae3-ba7c1dcd812f"
|
|
68
|
+
|
|
69
|
+
my_data_request = client.create_data_request(
|
|
70
|
+
aoi_id=my_aoi.id,
|
|
71
|
+
dataset_id=planet_forest_carbon_diligence_id,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
print(client.get_data_request(my_data_request.id).status)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Create a reprojection using the Cecil client (once data request is completed)
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
my_reprojection = client.create_reprojection(
|
|
81
|
+
data_request_id=my_data_request.id,
|
|
82
|
+
crs="EPSG:4326",
|
|
83
|
+
resolution=0.005,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
print(client.get_reprojection(my_reprojection.id).status)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Query data (once reprojection is completed)
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
df = client.query(f'''
|
|
93
|
+
SELECT *
|
|
94
|
+
FROM
|
|
95
|
+
planet.forest_carbon_diligence
|
|
96
|
+
WHERE
|
|
97
|
+
reprojection_id = '{my_reprojection.id}'
|
|
98
|
+
''')
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Other client methods:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
client.list_aois()
|
|
105
|
+
|
|
106
|
+
client.get_aoi(my_aoi.id)
|
|
107
|
+
|
|
108
|
+
client.list_data_requests()
|
|
109
|
+
|
|
110
|
+
client.get_data_request(my_data_request.id)
|
|
111
|
+
|
|
112
|
+
client.list_reprojections()
|
|
113
|
+
|
|
114
|
+
client.get_reprojection(my_reprojection.id)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
`cecil` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
cecil-0.0.7/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Cecil SDK
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/cecil-sdk)
|
|
4
|
+
[](https://pypi.org/project/cecil-sdk)
|
|
5
|
+
|
|
6
|
+
-----
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Authentication](#authentication)
|
|
12
|
+
- [License](#license)
|
|
13
|
+
- [Examples](#examples)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
pip install cecil
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Authentication
|
|
22
|
+
|
|
23
|
+
Set `CECIL_API_KEY` environment variable to your Cecil API key.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### Create an AOI and data request using the Cecil client
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import cecil
|
|
31
|
+
|
|
32
|
+
client = cecil.Client()
|
|
33
|
+
|
|
34
|
+
my_aoi = client.create_aoi(
|
|
35
|
+
name="My AOI",
|
|
36
|
+
geometry={
|
|
37
|
+
"type": "Polygon",
|
|
38
|
+
"coordinates": [
|
|
39
|
+
[
|
|
40
|
+
[145.410408835, -42.004083838],
|
|
41
|
+
[145.410408835, -42.004203978],
|
|
42
|
+
[145.410623191, -42.004203978],
|
|
43
|
+
[145.410623191, -42.004083838],
|
|
44
|
+
[145.410408835, -42.004083838],
|
|
45
|
+
]
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Get dataset ID from docs.cecil.earth -> Datasets
|
|
51
|
+
planet_forest_carbon_diligence_id = "c2dd4f55-56f6-4d05-aae3-ba7c1dcd812f"
|
|
52
|
+
|
|
53
|
+
my_data_request = client.create_data_request(
|
|
54
|
+
aoi_id=my_aoi.id,
|
|
55
|
+
dataset_id=planet_forest_carbon_diligence_id,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
print(client.get_data_request(my_data_request.id).status)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Create a reprojection using the Cecil client (once data request is completed)
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
my_reprojection = client.create_reprojection(
|
|
65
|
+
data_request_id=my_data_request.id,
|
|
66
|
+
crs="EPSG:4326",
|
|
67
|
+
resolution=0.005,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
print(client.get_reprojection(my_reprojection.id).status)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Query data (once reprojection is completed)
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
df = client.query(f'''
|
|
77
|
+
SELECT *
|
|
78
|
+
FROM
|
|
79
|
+
planet.forest_carbon_diligence
|
|
80
|
+
WHERE
|
|
81
|
+
reprojection_id = '{my_reprojection.id}'
|
|
82
|
+
''')
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Other client methods:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
client.list_aois()
|
|
89
|
+
|
|
90
|
+
client.get_aoi(my_aoi.id)
|
|
91
|
+
|
|
92
|
+
client.list_data_requests()
|
|
93
|
+
|
|
94
|
+
client.get_data_request(my_data_request.id)
|
|
95
|
+
|
|
96
|
+
client.list_reprojections()
|
|
97
|
+
|
|
98
|
+
client.get_reprojection(my_reprojection.id)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
`cecil` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
cecil-0.0.7/__about__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.7"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cecil"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = 'Python SDK for Cecil Earth'
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"pydantic",
|
|
20
|
+
"requests",
|
|
21
|
+
"snowflake-connector-python[pandas]"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[tool.hatch.version]
|
|
25
|
+
path = "__about__.py"
|
|
26
|
+
|
|
27
|
+
[tool.hatch.envs.hatch-test]
|
|
28
|
+
extra-dependencies = [
|
|
29
|
+
"responses"
|
|
30
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .client import Client
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
from requests import auth
|
|
7
|
+
|
|
8
|
+
import snowflake.connector
|
|
9
|
+
|
|
10
|
+
from .models import (
|
|
11
|
+
AOI,
|
|
12
|
+
AOICreate,
|
|
13
|
+
DataRequest,
|
|
14
|
+
DataRequestCreate,
|
|
15
|
+
Reprojection,
|
|
16
|
+
ReprojectionCreate,
|
|
17
|
+
SnowflakeCredentials,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# TODO: Documentation (Google style)
|
|
21
|
+
# TODO: Add HTTP retries
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Client:
|
|
25
|
+
def __init__(self, env="dev"):
|
|
26
|
+
self._api_auth = None
|
|
27
|
+
self._base_url = f"https://{env}-api.cecil.earth" # TODO: hard-code to prod URL
|
|
28
|
+
self._snowflake_creds = None
|
|
29
|
+
|
|
30
|
+
def create_aoi(self, name: str, geometry: Dict) -> AOI:
|
|
31
|
+
# TODO: validate geometry
|
|
32
|
+
res = self._post(url="/v0/aois", model=AOICreate(name=name, geometry=geometry))
|
|
33
|
+
return AOI(**res)
|
|
34
|
+
|
|
35
|
+
def get_aoi(self, id: str) -> AOI:
|
|
36
|
+
res = self._get(url=f"/v0/aois/{id}")
|
|
37
|
+
return AOI(**res)
|
|
38
|
+
|
|
39
|
+
def list_aois(self) -> List[AOI]:
|
|
40
|
+
res = self._get(url="/v0/aois")
|
|
41
|
+
return [AOI(**record) for record in res["records"]]
|
|
42
|
+
|
|
43
|
+
def create_data_request(self, aoi_id: str, dataset_id: str) -> DataRequest:
|
|
44
|
+
res = self._post(
|
|
45
|
+
url="/v0/data-requests",
|
|
46
|
+
model=DataRequestCreate(aoi_id=aoi_id, dataset_id=dataset_id),
|
|
47
|
+
)
|
|
48
|
+
return DataRequest(**res)
|
|
49
|
+
|
|
50
|
+
def get_data_request(self, id: str) -> DataRequest:
|
|
51
|
+
res = self._get(url=f"/v0/data-requests/{id}")
|
|
52
|
+
return DataRequest(**res)
|
|
53
|
+
|
|
54
|
+
def list_data_requests(self):
|
|
55
|
+
res = self._get(url="/v0/data-requests")
|
|
56
|
+
return [DataRequest(**record) for record in res["records"]]
|
|
57
|
+
|
|
58
|
+
def create_reprojection(
|
|
59
|
+
self, data_request_id: str, crs: str, resolution: float
|
|
60
|
+
) -> Reprojection:
|
|
61
|
+
# TODO: check if data request is completed before creating reprojection
|
|
62
|
+
res = self._post(
|
|
63
|
+
url="/v0/reprojections",
|
|
64
|
+
model=ReprojectionCreate(
|
|
65
|
+
data_request_id=data_request_id,
|
|
66
|
+
crs=crs,
|
|
67
|
+
resolution=resolution,
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
return Reprojection(**res)
|
|
71
|
+
|
|
72
|
+
def get_reprojection(self, id: str) -> Reprojection:
|
|
73
|
+
res = self._get(url=f"/v0/reprojections/{id}")
|
|
74
|
+
return Reprojection(**res)
|
|
75
|
+
|
|
76
|
+
def list_reprojections(self) -> List[Reprojection]:
|
|
77
|
+
res = self._get(url="/v0/reprojections")
|
|
78
|
+
return [Reprojection(**record) for record in res["records"]]
|
|
79
|
+
|
|
80
|
+
def query(self, sql):
|
|
81
|
+
if self._snowflake_creds is None:
|
|
82
|
+
res = self._get(url="/v0/data-access-credentials")
|
|
83
|
+
self._snowflake_creds = SnowflakeCredentials(**res)
|
|
84
|
+
|
|
85
|
+
with snowflake.connector.connect(
|
|
86
|
+
account=self._snowflake_creds.account.get_secret_value(),
|
|
87
|
+
user=self._snowflake_creds.user.get_secret_value(),
|
|
88
|
+
password=self._snowflake_creds.password.get_secret_value(),
|
|
89
|
+
) as conn:
|
|
90
|
+
df = conn.cursor().execute(sql).fetch_pandas_all()
|
|
91
|
+
df.columns = [x.lower() for x in df.columns]
|
|
92
|
+
|
|
93
|
+
return df
|
|
94
|
+
|
|
95
|
+
def _request(self, method: str, url: str, **kwargs) -> Dict:
|
|
96
|
+
|
|
97
|
+
self._set_auth()
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
r = requests.request(
|
|
101
|
+
method=method,
|
|
102
|
+
url=self._base_url + url,
|
|
103
|
+
auth=self._api_auth,
|
|
104
|
+
timeout=None,
|
|
105
|
+
**kwargs,
|
|
106
|
+
)
|
|
107
|
+
r.raise_for_status()
|
|
108
|
+
return r.json()
|
|
109
|
+
|
|
110
|
+
except requests.exceptions.ConnectionError as err:
|
|
111
|
+
raise ValueError("Connection error") from err
|
|
112
|
+
except requests.exceptions.HTTPError as err:
|
|
113
|
+
if err.response.status_code == 403:
|
|
114
|
+
raise ValueError("Authentication error") from err
|
|
115
|
+
else:
|
|
116
|
+
raise
|
|
117
|
+
|
|
118
|
+
def _get(self, url: str, **kwargs) -> Dict:
|
|
119
|
+
return self._request(method="get", url=url, **kwargs)
|
|
120
|
+
|
|
121
|
+
def _post(self, url: str, model: BaseModel, **kwargs) -> Dict:
|
|
122
|
+
return self._request(
|
|
123
|
+
method="post", url=url, json=model.model_dump(by_alias=True), **kwargs
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def _set_auth(self) -> None:
|
|
127
|
+
try:
|
|
128
|
+
api_key = os.environ["CECIL_API_KEY"]
|
|
129
|
+
self._api_auth = auth.HTTPBasicAuth(username=api_key, password="")
|
|
130
|
+
except KeyError:
|
|
131
|
+
raise ValueError("environment variable CECIL_API_KEY not set") from None
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, SecretStr
|
|
6
|
+
from pydantic.alias_generators import to_camel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SubRequestStatus(str, Enum):
|
|
10
|
+
COMPLETED = "completed"
|
|
11
|
+
FAILED = "failed"
|
|
12
|
+
PROCESSING = "processing"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DataRequestStatus(str, Enum):
|
|
16
|
+
COMPLETED = "completed"
|
|
17
|
+
FAILED = "failed"
|
|
18
|
+
PROCESSING = "processing"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AOI(BaseModel):
|
|
22
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
23
|
+
id: str
|
|
24
|
+
name: str
|
|
25
|
+
geometry: Dict
|
|
26
|
+
hectares: float
|
|
27
|
+
created: datetime.datetime
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class AOICreate(BaseModel):
|
|
31
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
32
|
+
name: str
|
|
33
|
+
geometry: Dict
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SubRequest(BaseModel):
|
|
37
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
38
|
+
external_id: str
|
|
39
|
+
description: str
|
|
40
|
+
status: SubRequestStatus
|
|
41
|
+
error_message: Optional[str]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class DataRequest(BaseModel):
|
|
45
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
46
|
+
id: str
|
|
47
|
+
aoi_id: str
|
|
48
|
+
dataset_id: str
|
|
49
|
+
sub_requests: List[SubRequest]
|
|
50
|
+
status: DataRequestStatus
|
|
51
|
+
created: datetime.datetime
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DataRequestCreate(BaseModel):
|
|
55
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
56
|
+
aoi_id: str
|
|
57
|
+
dataset_id: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Reprojection(BaseModel):
|
|
61
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
62
|
+
id: str
|
|
63
|
+
data_request_id: str
|
|
64
|
+
crs: str
|
|
65
|
+
resolution: float
|
|
66
|
+
created: datetime.datetime
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ReprojectionCreate(BaseModel):
|
|
70
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
71
|
+
data_request_id: str
|
|
72
|
+
crs: str
|
|
73
|
+
resolution: float
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SnowflakeCredentials(BaseModel):
|
|
77
|
+
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
|
78
|
+
account: SecretStr
|
|
79
|
+
user: SecretStr
|
|
80
|
+
password: SecretStr
|
|
File without changes
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import responses
|
|
2
|
+
|
|
3
|
+
from src.cecil.client import Client
|
|
4
|
+
from src.cecil.models import DataRequest, DataRequestStatus
|
|
5
|
+
|
|
6
|
+
FROZEN_TIME = "2024-01-01T00:00:00.000Z"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_client_class():
|
|
10
|
+
client = Client()
|
|
11
|
+
assert client._base_url == "https://dev-api.cecil.earth"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@responses.activate
|
|
15
|
+
def test_client_create_data_request():
|
|
16
|
+
responses.add(
|
|
17
|
+
responses.POST,
|
|
18
|
+
"https://dev-api.cecil.earth/v0/data-requests",
|
|
19
|
+
json={
|
|
20
|
+
"id": "id",
|
|
21
|
+
"aoiId": "aoi_id",
|
|
22
|
+
"datasetId": "dataset_id",
|
|
23
|
+
"subRequests": [],
|
|
24
|
+
"status": "processing",
|
|
25
|
+
"created": FROZEN_TIME,
|
|
26
|
+
},
|
|
27
|
+
status=201,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
client = Client()
|
|
31
|
+
res = client.create_data_request("aoi_id", "dataset_id")
|
|
32
|
+
|
|
33
|
+
assert res == DataRequest(
|
|
34
|
+
id="id",
|
|
35
|
+
aoiId="aoi_id",
|
|
36
|
+
datasetId="dataset_id",
|
|
37
|
+
subRequests=[],
|
|
38
|
+
status="processing",
|
|
39
|
+
created="2024-01-01T00:00:00.000Z",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@responses.activate
|
|
44
|
+
def test_client_list_data_requests():
|
|
45
|
+
responses.add(
|
|
46
|
+
responses.GET,
|
|
47
|
+
"https://dev-api.cecil.earth/v0/data-requests",
|
|
48
|
+
json={
|
|
49
|
+
"records": [
|
|
50
|
+
{
|
|
51
|
+
"id": "data_request_id_1",
|
|
52
|
+
"aoiId": "aoi_id",
|
|
53
|
+
"datasetId": "dataset_id",
|
|
54
|
+
"subRequests": [], # TODO: Add some SubRequests
|
|
55
|
+
"status": "processing",
|
|
56
|
+
"created": "2024-09-19T04:45:57.561Z",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "data_request_id_2",
|
|
60
|
+
"aoiId": "aoi_id",
|
|
61
|
+
"datasetId": "dataset_id",
|
|
62
|
+
"subRequests": [], # TODO: Add some SubRequests
|
|
63
|
+
"status": "completed",
|
|
64
|
+
"created": "2024-09-19T04:54:38.252Z",
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
client = Client()
|
|
71
|
+
data_requests = client.list_data_requests()
|
|
72
|
+
|
|
73
|
+
assert data_requests == [
|
|
74
|
+
DataRequest(
|
|
75
|
+
id="data_request_id_1",
|
|
76
|
+
aoiId="aoi_id",
|
|
77
|
+
datasetId="dataset_id",
|
|
78
|
+
subRequests=[],
|
|
79
|
+
status=DataRequestStatus.PROCESSING,
|
|
80
|
+
created="2024-09-19T04:45:57.561Z",
|
|
81
|
+
),
|
|
82
|
+
DataRequest(
|
|
83
|
+
id="data_request_id_2",
|
|
84
|
+
aoiId="aoi_id",
|
|
85
|
+
datasetId="dataset_id",
|
|
86
|
+
subRequests=[],
|
|
87
|
+
status=DataRequestStatus.COMPLETED,
|
|
88
|
+
created="2024-09-19T04:54:38.252Z",
|
|
89
|
+
),
|
|
90
|
+
]
|