Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

adamapi

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

adamapi - npm Package Compare versions

Comparing version
2.0.11
to
2.1.0
+20
LICENSE
Copyright (c) 2022 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
[build-system]
requires = [
"setuptools>=42",
"wheel"
]
build-backend = "setuptools.build_meta"
# Installation
### Versioning
1. adamapi==2.0.11 , This package works only with ADAMCORE 1.
2. adamapi==2.1.0, This pachage works only with ADAMCORE 2.
## Requirements
```bash
sudo apt-get install python3-venv python3-gdal gdal-bin
```
## Install with pip
```bash
VENVNAME="adamapi"
python3 -m venv "${VENVNAME}"
source "${VENVNAME}/bin/activate";
python3 -m pip install --upgrade pip;
pip install adamapi
ln -s "/usr/lib/python3/dist-packages/osgeo" "${VENVNAME}/lib/python3.8/site-packages/osgeo"
```
# API DEFINITIONS
This document briefly describes the ADMAPI functionalities.<br>
The ADAMAPI library is divided in 4 modules:
1. Auth --> the authorization module
2. Datasets --> to get the list of datasets
3. Search --> to get the lists of products, including associated metadata (e.g. geometry, cloud cover, orbit, tile, ...)
4. GetData --> to retrieve the product(s), including options to subset in space and time in the native data granularity and reduced processing capacity
## 1 - Auth
This module takes care of user authentication and authorization.<br>
Without instancing an object of this module other components don't work.<br>
Auth module is based on the ADAMAPI_KEY, a key that uniquelly identifies the user.
**Class contructor and parameters**
```python
from adamapi import Auth
a = Auth()
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
**Public methods and parameters**
* **.setKey()** --> To setup the ADAMAPI_KEY<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The ADAMAPI_KEY |
* **.setAdamCore()** --> To setup the url of the ADAM-CORE endpoint<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The url like https://test.adamplatform.eu |
* **.authorize()** --> to instanciate an auth object<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
* **.getAuthToken()** --> to get the authorization token<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
### 1.1 - ADAMAPI_KEY retrieval
To get the ADAMAPI_KEY, you need to access your ADAM portal and:<br>
1. Select the "user icon" on the top right
2. Expand / click the "USERNAME"
3. Click on the "Api Key" to display your key
<br>
*Command-line ADAMAPI_KEY retrieval TBP*
### 1.2 - ADAMAPI_KEY setup
There are three methods to setup the ADAMAPI_KEY and the ADAM-CORE instance:
1. use the method setKey() and setAdamCore()
```python
from adamapi import Auth
a = Auth()
a.setKey('<ADAMAPI_KEY>')
a.setAdamCore('https://test.adamplatform.eu')
```
2. Export two envars like
```bash
#open a Terminal and type:
export ADAMAPI_KEY='<ADAMAPI_KEY>'
export ADAMAPI_URL='https://test.adamplatform.eu'
```
3. create a file called **.adamapirc** in the user home directory with the following content
```text
key=<ADAMAPI_KEY>
url=https://test.adamplatform.eu
```
### 1.3 - Examples
After ADAMAPI_KEY has been set up, an auth instance can be created with:
```python
from adamapi import Auth
a = Auth()
a.authorize()
```
After authorize method you can retrive your autho token:
```python
from adamapi import Auth
a = Auth()
a.authorize()
a.getAuthToken()
```
## 2 - Datasets
This module provides datasets discovery functionality.
**Class contructor and parameters**
```python
from adamapi import Datasets
datasets = Datasets( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in the previous section |
**Public methods and parameters**
* **.getDatasets()** --> To retrieve datasets list <br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | False | str | | The datasetId. |
| page | False | numeric | 0 | Indicats a specific page |
| maxRecords | False | numeric | 10 | Max number of results in output. |
This .getDatasets() function can be used to retrive additional filters which are described in the key **filtersEnabled** (if exists).
### 2.1 Examples
This module can be used in 2 different ways.
1. To list all available datasets:
```python
datasets = Datasets(a)
print(datasets.getDatasets())
```
2. To get detailed metadata about a specific dataset
```python
datasets = Datasets(a)
print( datasets.getDatasets( '{{ID:DATASET}}' , page=0 , maxRecords=10 ) )
```
3. To get filtersEnabled. To use this additional filters see first example in Search section.
```python
datasets = Datasets(a)
out=datasets.getDatasets("{{ID:DATASET}}")
print(out["filtersEnabled"])
```
## 3 - Search
This module provides discovery functionality through the products available on the ADAM instance.
**Class contructor and parameters**
```python
from adamapi import Search
search = Search( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in section 1-Auth |
**Public methods and parameters**
* **.getProducts()** --> To retrieve datasets list and metadata<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId. |
| maxRecords | False | int | 10 | number of records |
| startIndex | False | int | 0 | starting record index |
| startDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the start date |
| endDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the end date |
| geometry | True | str or geojson | | GeoJson geometry,[geojson format](https://tools.ietf.org/html/rfc7946) [appendix](#geometry)|
### 3.1 Examples
1. Example1:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0,platform="{{VALUE}}")
```
2. Example2:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0)
```
## 4 - GetData
This module provides data access of raster, spatial subset, timeseries in the native data granularity and reduced processing capacity.
**Class contructor and parameters**
```python
from adamapi import GetData
data=GetData(a)
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth Instance | | The ADAMAPI authorized instance obtained in the section 1-Auth |
**Public methods and parameters**
* **.getData()** --> To retrieve a specific product or a dataset in its native granularity, to get a subset of it, to perform a timeseries or to exec simple processing <br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId |
| 1 | True | str | GetFile | request type. available values: GetFile,GetSubset, GetTimeseries and GetProcessing |
| asynchronous | False | boolean | False | rappesents how the request will be performed |
| compress | False | boolean | False | return a zip file |
| rest | False | boolean | True | perform RESTful order ignoring explorer state on the server and equalization configured using the explorer gui |
| filters | True | json | {} | json object with filters parameter. startDate and endDate are required inside it |
| options | False | json | {} | request option |
| outputDir | False | str | `adamapiresults/` | set a different download directory inside `adamapiresult/` main directory |
### 4.1 Examples
```python
data=GetData(a)
#to retrive a specific product
image = data.getData('{{ID:DATASET}}',"GetFile",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"productId":'{{PRODUCTID}}'},outputDir='{{OUTPUT_DIR}}')
#to retrieve a dataset in its native granularity
data=GetData(self.a)
image = data.getData('{{ID:DATASET}}',"GetFile",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},outputDir='{{OUTPUT_DIR}}')
```
For the GetSubset,GetTimeseries and GetProcessing requests you need to add the `options` parameter with these constraints : [output formats](#output-formats) and [functions](#processing-function)(only for processing request)
```python
#subset example
image = data.getData('{{ID:DATASET}}',"GetSubset",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#timeseries example
image = data.getData('{{ID:DATASET}}',"GetTimeseries",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#processing example
image = data.getData('{{ID:DATASET}}',"GetProcessing",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMAT}}',"function":'{{FUNCTION}}'},outputDir='{{OUTPUT_DIR}}')
```
### 4.3 Asyncronous Example
```python
#1. execute the request
image = data.getData('{{ID:DATASET}}',"GetSubset",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#2. check the status
stat=data.getData(datasetId,"GetSubset",asynchronous=True,id=str(image.pk))
while stat.status != "completed":
time.sleep(1)
stat=data.getData(datasetId,"GetSubset",asynchronous=True,id=str(image.pk))
#3. download the zip,unzip it and remove the zip (optional)
for res in stat.list:
if res["status"] == "failed":
print(res["exit_code"])
else:
r=self.a.client(res["download"]["url"],{},"GET")
with open(str(res["download"]["url"].split("/")[4])+"_"+str(res["download"]["url"].split("/")[5]), 'wb' ) as f:
f.write( r.content )
```
# Appendix 1 - Data format
## date and date+time
Supported string date/date+time format are:
* '%Y-%m-%dT%H:%M:%S',
* '%Y-%m-%dT%H:%M:%SZ',
* '%Y-%m-%d'
### GeoJson
Geometry have to follow the latest geojson standard [rfc7946](https://tools.ietf.org/html/rfc7946)<br>
In particular Polygons and MultiPolygons should follow the right-hand rule<br>
### Geometry
```python
#This geometry will return all the results it has intersected within it
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [ 43.916666667, 15.416666667 ] , [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ] ] ] }
```
```python
#This geometry will return all the results it has intersected on its outside
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.84986877441406,15.925676536359038 ], [ 44.6539306640625,15.950766025306109 ],[ 44.681396484375,15.194084972583916 ], [ 43.8189697265625,15.20998780073036 ], [ 43.84986877441406,15.925676536359038 ] ] ] }
```
### Output Formats
| request | output format |
| ---- | ---- |
| GetFile | - |
| GetSubset | tiff,png |
| GetTimeseries | json,csv |
| GetProcessing | tiff,png |
### Processing Function
| type | description |
| ---- | ---- |
| average | execute the average from the products |
| overlap | execute the products overlap without any specific strategy |
| mosterecent | puts on the top the most recent product |
| leastrecent | puts on top the least recent product |
| minvalue | for each pixel, puts on top the minimum value of the pixel |
| maxvalue | for each pixel, puts on top the maximum value of the pixel |
Metadata-Version: 2.1
Name: adamapi
Version: 2.1.0
Summary: Python Adam API
Home-page: https://git.services.meeo.it/das/adamapi
Author: MEEO s.r.l.
Author-email: info@meeo.it
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Unix
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE
# Installation
### Versioning
1. adamapi==2.0.11 , This package works only with ADAMCORE 1.
2. adamapi==2.1.0, This pachage works only with ADAMCORE 2.
## Requirements
```bash
sudo apt-get install python3-venv python3-gdal gdal-bin
```
## Install with pip
```bash
VENVNAME="adamapi"
python3 -m venv "${VENVNAME}"
source "${VENVNAME}/bin/activate";
python3 -m pip install --upgrade pip;
pip install adamapi
ln -s "/usr/lib/python3/dist-packages/osgeo" "${VENVNAME}/lib/python3.8/site-packages/osgeo"
```
# API DEFINITIONS
This document briefly describes the ADMAPI functionalities.<br>
The ADAMAPI library is divided in 4 modules:
1. Auth --> the authorization module
2. Datasets --> to get the list of datasets
3. Search --> to get the lists of products, including associated metadata (e.g. geometry, cloud cover, orbit, tile, ...)
4. GetData --> to retrieve the product(s), including options to subset in space and time in the native data granularity and reduced processing capacity
## 1 - Auth
This module takes care of user authentication and authorization.<br>
Without instancing an object of this module other components don't work.<br>
Auth module is based on the ADAMAPI_KEY, a key that uniquelly identifies the user.
**Class contructor and parameters**
```python
from adamapi import Auth
a = Auth()
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
**Public methods and parameters**
* **.setKey()** --> To setup the ADAMAPI_KEY<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The ADAMAPI_KEY |
* **.setAdamCore()** --> To setup the url of the ADAM-CORE endpoint<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The url like https://test.adamplatform.eu |
* **.authorize()** --> to instanciate an auth object<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
* **.getAuthToken()** --> to get the authorization token<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
### 1.1 - ADAMAPI_KEY retrieval
To get the ADAMAPI_KEY, you need to access your ADAM portal and:<br>
1. Select the "user icon" on the top right
2. Expand / click the "USERNAME"
3. Click on the "Api Key" to display your key
<br>
*Command-line ADAMAPI_KEY retrieval TBP*
### 1.2 - ADAMAPI_KEY setup
There are three methods to setup the ADAMAPI_KEY and the ADAM-CORE instance:
1. use the method setKey() and setAdamCore()
```python
from adamapi import Auth
a = Auth()
a.setKey('<ADAMAPI_KEY>')
a.setAdamCore('https://test.adamplatform.eu')
```
2. Export two envars like
```bash
#open a Terminal and type:
export ADAMAPI_KEY='<ADAMAPI_KEY>'
export ADAMAPI_URL='https://test.adamplatform.eu'
```
3. create a file called **.adamapirc** in the user home directory with the following content
```text
key=<ADAMAPI_KEY>
url=https://test.adamplatform.eu
```
### 1.3 - Examples
After ADAMAPI_KEY has been set up, an auth instance can be created with:
```python
from adamapi import Auth
a = Auth()
a.authorize()
```
After authorize method you can retrive your autho token:
```python
from adamapi import Auth
a = Auth()
a.authorize()
a.getAuthToken()
```
## 2 - Datasets
This module provides datasets discovery functionality.
**Class contructor and parameters**
```python
from adamapi import Datasets
datasets = Datasets( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in the previous section |
**Public methods and parameters**
* **.getDatasets()** --> To retrieve datasets list <br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | False | str | | The datasetId. |
| page | False | numeric | 0 | Indicats a specific page |
| maxRecords | False | numeric | 10 | Max number of results in output. |
This .getDatasets() function can be used to retrive additional filters which are described in the key **filtersEnabled** (if exists).
### 2.1 Examples
This module can be used in 2 different ways.
1. To list all available datasets:
```python
datasets = Datasets(a)
print(datasets.getDatasets())
```
2. To get detailed metadata about a specific dataset
```python
datasets = Datasets(a)
print( datasets.getDatasets( '{{ID:DATASET}}' , page=0 , maxRecords=10 ) )
```
3. To get filtersEnabled. To use this additional filters see first example in Search section.
```python
datasets = Datasets(a)
out=datasets.getDatasets("{{ID:DATASET}}")
print(out["filtersEnabled"])
```
## 3 - Search
This module provides discovery functionality through the products available on the ADAM instance.
**Class contructor and parameters**
```python
from adamapi import Search
search = Search( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in section 1-Auth |
**Public methods and parameters**
* **.getProducts()** --> To retrieve datasets list and metadata<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId. |
| maxRecords | False | int | 10 | number of records |
| startIndex | False | int | 0 | starting record index |
| startDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the start date |
| endDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the end date |
| geometry | True | str or geojson | | GeoJson geometry,[geojson format](https://tools.ietf.org/html/rfc7946) [appendix](#geometry)|
### 3.1 Examples
1. Example1:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0,platform="{{VALUE}}")
```
2. Example2:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0)
```
## 4 - GetData
This module provides data access of raster, spatial subset, timeseries in the native data granularity and reduced processing capacity.
**Class contructor and parameters**
```python
from adamapi import GetData
data=GetData(a)
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth Instance | | The ADAMAPI authorized instance obtained in the section 1-Auth |
**Public methods and parameters**
* **.getData()** --> To retrieve a specific product or a dataset in its native granularity, to get a subset of it, to perform a timeseries or to exec simple processing <br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId |
| 1 | True | str | GetFile | request type. available values: GetFile,GetSubset, GetTimeseries and GetProcessing |
| asynchronous | False | boolean | False | rappesents how the request will be performed |
| compress | False | boolean | False | return a zip file |
| rest | False | boolean | True | perform RESTful order ignoring explorer state on the server and equalization configured using the explorer gui |
| filters | True | json | {} | json object with filters parameter. startDate and endDate are required inside it |
| options | False | json | {} | request option |
| outputDir | False | str | `adamapiresults/` | set a different download directory inside `adamapiresult/` main directory |
### 4.1 Examples
```python
data=GetData(a)
#to retrive a specific product
image = data.getData('{{ID:DATASET}}',"GetFile",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"productId":'{{PRODUCTID}}'},outputDir='{{OUTPUT_DIR}}')
#to retrieve a dataset in its native granularity
data=GetData(self.a)
image = data.getData('{{ID:DATASET}}',"GetFile",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},outputDir='{{OUTPUT_DIR}}')
```
For the GetSubset,GetTimeseries and GetProcessing requests you need to add the `options` parameter with these constraints : [output formats](#output-formats) and [functions](#processing-function)(only for processing request)
```python
#subset example
image = data.getData('{{ID:DATASET}}',"GetSubset",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#timeseries example
image = data.getData('{{ID:DATASET}}',"GetTimeseries",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#processing example
image = data.getData('{{ID:DATASET}}',"GetProcessing",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMAT}}',"function":'{{FUNCTION}}'},outputDir='{{OUTPUT_DIR}}')
```
### 4.3 Asyncronous Example
```python
#1. execute the request
image = data.getData('{{ID:DATASET}}',"GetSubset",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#2. check the status
stat=data.getData(datasetId,"GetSubset",asynchronous=True,id=str(image.pk))
while stat.status != "completed":
time.sleep(1)
stat=data.getData(datasetId,"GetSubset",asynchronous=True,id=str(image.pk))
#3. download the zip,unzip it and remove the zip (optional)
for res in stat.list:
if res["status"] == "failed":
print(res["exit_code"])
else:
r=self.a.client(res["download"]["url"],{},"GET")
with open(str(res["download"]["url"].split("/")[4])+"_"+str(res["download"]["url"].split("/")[5]), 'wb' ) as f:
f.write( r.content )
```
# Appendix 1 - Data format
## date and date+time
Supported string date/date+time format are:
* '%Y-%m-%dT%H:%M:%S',
* '%Y-%m-%dT%H:%M:%SZ',
* '%Y-%m-%d'
### GeoJson
Geometry have to follow the latest geojson standard [rfc7946](https://tools.ietf.org/html/rfc7946)<br>
In particular Polygons and MultiPolygons should follow the right-hand rule<br>
### Geometry
```python
#This geometry will return all the results it has intersected within it
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [ 43.916666667, 15.416666667 ] , [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ] ] ] }
```
```python
#This geometry will return all the results it has intersected on its outside
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.84986877441406,15.925676536359038 ], [ 44.6539306640625,15.950766025306109 ],[ 44.681396484375,15.194084972583916 ], [ 43.8189697265625,15.20998780073036 ], [ 43.84986877441406,15.925676536359038 ] ] ] }
```
### Output Formats
| request | output format |
| ---- | ---- |
| GetFile | - |
| GetSubset | tiff,png |
| GetTimeseries | json,csv |
| GetProcessing | tiff,png |
### Processing Function
| type | description |
| ---- | ---- |
| average | execute the average from the products |
| overlap | execute the products overlap without any specific strategy |
| mosterecent | puts on the top the most recent product |
| leastrecent | puts on top the least recent product |
| minvalue | for each pixel, puts on top the minimum value of the pixel |
| maxvalue | for each pixel, puts on top the maximum value of the pixel |
requests>=2.22.0
imageio==2.9.0
tqdm==4.62.3
numpy==1.21.2
python-dateutil==2.8.2
matplotlib==3.4.3
certifi==2021.5.30
charset-normalizer==2.0.6
cycler==0.10.0
idna==3.2
kiwisolver==1.3.2
Pillow==8.3.2
pyparsing==2.4.7
six==1.16.0
urllib3==1.26.7
LICENSE
README.md
pyproject.toml
setup.py
src/adamapi/__init__.py
src/adamapi/authorization.py
src/adamapi/datasets.py
src/adamapi/get_data.py
src/adamapi/search.py
src/adamapi.egg-info/PKG-INFO
src/adamapi.egg-info/SOURCES.txt
src/adamapi.egg-info/dependency_links.txt
src/adamapi.egg-info/requires.txt
src/adamapi.egg-info/top_level.txt
"""
Copyright (c) 2020 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
class AdamApiError( Exception ):
"""Base class for exceptions on the adamapi module."""
pass
class AdamApiMessage( Exception ):
"""Base class for adamapi mesage"""
def __init__(self,json):
self.pk=json["id"] if "id" in json else ""
self.status=json["status"] if "status" in json else ""
self.location = json["location"] if "location" in json else ""
self.error = json["error"] if "error" in json else ""
self.list = json["tasks"] if "tasks" in json else ""
from . import authorization
from . import datasets
from . import get_data
from . import search
Auth = authorization.Auth
Datasets = datasets.Datasets
GetData = get_data.GetData
Search = search.Search
"""
Copyright (c) 2022 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import os
import requests
import re
import logging
from datetime import datetime,timedelta
logger = logging.getLogger( 'adamapi' )
from . import AdamApiError
class Auth():
def __init__( self, key=None, url=None ):
"""
Authorization class used to manage users credentials
"""
self.key = key
self.url = url
self.authorized = False
self.access_obj=None
self.lock=False
def authorize( self ):
"""
try to autorize the adamapi to the target adam instance
"""
#verify if key are valid
self._check()
url = os.path.join( self.url,'apis','v1','authorization', 'adamapi' )
headers={ 'Authorization': self.key }
r=requests.post( url,data={},headers=headers )
res = r.json()
if r.status_code !=200:
raise AdamApiError( res['title'] )
else:
logger.info( res )
self.authorized = True
self.access_obj= res
return res
def getAuthToken(self):
return {
"authorization_token" : self.access_obj["access_token"],
"expires_at" : self.access_obj["expires_at"]
}
def _check( self ):
"""
verify if the user key and the adam url are valid
"""
self.getKey()
self.getAdamCore()
if self.key is None:
raise AdamApiError( "key can not be None" )
if self.url is None:
raise AdamApiError( "url (adam endpoint) can not be None" )
def setKey( self, key ):
"""
set the user key
"""
self.key = key
def setAdamCore( self, url ):
"""
set the adam endpoint url
"""
self.url = url
def getKey( self ):
"""
key priority:
1 - use the key declared on this module
2 - use a key exported as envvars
3 - try to retrieve the key from $HOME/.adamapirc
"""
if self.key is not None:
pass
elif os.environ.get( 'ADAMAPI_KEY') is not None:
self.key = os.environ.get( 'ADAMAPI_KEY' )
logger.debug( 'Get key from envvar' )
else:
try:
self.key = self._getRc()[ 'key' ]
logger.debug( 'Get key from adamapirc' )
except:
None
if self.key is None: #again
logger.warning( "API key not specified" )
return self.key
def getAdamCore( self ):
"""
adam endpoint priority:
1 - use the url declared on this module
2 - use a url exported as envvars
3 - try to retrieve the url from $HOME/.adamapirc
"""
if self.url is not None:
pass
elif os.environ.get( 'ADAMAPI_URL') is not None:
self.url = os.environ.get( 'ADAMAPI_URL' )
logger.debug( 'Get url from envvar' )
else:
try:
self.url = self._getRc()[ 'url' ]
logger.debug( 'Get url from adamapirc' )
except:
None
if self.url is None: #again
logger.warning( "ADAM API endpoint not specified" )
return self.url
def _getRc( self ):
"""
check if ~/.adamapirc file exist ant try to extract url and key from it
"""
api_rc = os.environ.get( 'ADAMAPI_RC', os.path.expanduser( '~/.adamapirc' ) )
config_dict = {}
if os.path.isfile( api_rc ):
with open( api_rc ) as f:
for line in f.readlines():
line = line.strip()
if line.lstrip( '#' ) == line:
try:
key, val = line.split( '=', 1 )
config_dict[ key.strip() ] = val.strip()
except:
logger.warning( 'Invalid settings in "%s" - %s' %( api_rc, line ) )
return config_dict
def _checktokenExpire(self):
"""
check if token is expired
"""
if (datetime.strptime(self.access_obj['expires_at'],"%Y-%m-%dT%H:%M:%S.%fZ") - datetime.utcnow().replace(microsecond=0)) <= timedelta(minutes=15) :
return True
else:
return False
def _refreshToken(self):
"""
refresh tocken obj
"""
self.lock=True
params = {}
params["refresh_token"]=self.access_obj["refresh_token"]
self.access_obj = self.client(os.path.join( 'apis','v1', 'authorization', 'refresh' ), params, 'PUT').json()
self.lock=False
def client( self, query, params, request_type, authorization_required = True , force_raise = False ,enable_stream=False):
"""
The client method that perform the request appending the Authorization header
"""
#verify if the user already call the authorize method of the Auth instance
#if authorization_required and not self.authorized:
# self.authorize()
if not self.authorized and self.access_obj is not None :
raise AdamApiError("Unauthorized")
if not self.lock and self._checktokenExpire():
self._refreshToken()
#verify if the passed url already include the host or if the adamcore url have to be prepended
if re.match( r'^http[s]?://.+', query ):
url = query
else:
url = os.path.join( self.url, query )
if request_type not in [ 'GET', 'POST', 'PUT' ]:
raise AdamApiError( "Request type not supported" )
logger.debug( "%s request started", request_type )
if "\\" in url:
url = url.replace("\\","/")
if request_type == 'GET':
par = params.copy()
par["token"] = self.access_obj["access_token"]
r=requests.get( url, params=par ,stream=enable_stream)
elif request_type == 'POST':
par = params.copy()
par["token"] = self.access_obj["access_token"]
r=requests.post( url,data=par )
elif request_type == 'PUT':
r=requests.put( url,data=params )
logger.info(r.status_code)
if r.status_code in range(400,599):
if force_raise:
return r.raise_for_status()
else:
return r
else:
return r
"""
Copyright (c) 2022 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import os
import logging
logger=logging.getLogger('adamapi')
from . import AdamApiError
class Datasets():
def __init__(self, client):
self.client = client
self.LOG = logger
def getDatasets(self,datasetId=None,**kwargs):
params={}
params["client"]="adamapi"
if datasetId:
url=os.path.join("apis","v2","datasets",datasetId.split(":")[0])
else:
url=os.path.join("apis","v2","datasets","list")
if 'page' in kwargs:
params['page']=kwargs['page']
else:
params['page']=0
if 'maxRecords' in kwargs:
params['maxRecords']=kwargs['maxRecords']
else:
params['maxRecords']=10
r = self.client.client( url, params, 'GET' )
self.LOG.info( 'Datasets request executed' )
response = r.json()
return response
"""
Copyright (c) 2022 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import os
import time
from osgeo import ogr
import sys
import json
from tqdm import tqdm
import errno
import requests
import zipfile
from datetime import datetime
import re
import logging
logger=logging.getLogger('adamapi')
from . import AdamApiError,AdamApiMessage
class GetData(object):
def __init__(self,client):
self.LOG=logger
self.client=client
def getData(self,datasetId,request,asynchronous=False,compress=False,rest=True,filters={},options={},**kwargs):
"""
Method to retrive:
1) data in native format and native temporal resolution
2) a subset of data in native format and native temporal resolution
3) a timeseries of data in native format and native temporal resolution
4) a processing on a specific datasetId
@datasetId required
@asynchronous required (default False)
@startDate required
@endDate required
@schema optional ( required only for subset,timeseries and processing )
@geometry optional ( if schema is set, geometry param skipped in favor of the geometry param inside the schema if set )
@outputDir optional ( set a different download directory inside adamapiresult main directory
"""
#version 2.1-dev
#step 1 check params
#step 2 manage synchronously and asynchronously different temporal resolution datasets in the same way
#asynchronous management
if "outputDir" in kwargs:
output_dir = os.path.join("adamapiresult",kwargs["outputDir"])
else:
output_dir = "adamapiresult/"
self._checkDir(output_dir)
params,fname=self.checkParams( request,asynchronous, compress,rest,filters,options,kwargs)
startIndex=0
maxRecords=10
if asynchronous == True and "id" in params:
#get the order status
url=os.path.join( "apis", "v2", "orders", datasetId.split(":",1)[0], str(params["id"]) )
response_order_status=self.client.client(url,params,"GET",force_raise=True,enable_stream=False)
if response_order_status.status_code == 200:
return AdamApiMessage(response_order_status.json())
else:
raise AdamApiError(response_order_status.json())
#request management - the order submit url
url=os.path.join( "apis", "v2", "orders", datasetId.split(":",1)[0] )
#POST the order requests
response_order_submit = self.client.client(url,params,"POST",force_raise=False,enable_stream=False)
if response_order_submit.status_code==200:
if asynchronous == False:
#get the order status
url=os.path.join( "apis", "v2", "orders", datasetId.split(":",1)[0], str(response_order_submit.json()["id"]) )
response_order_status=self.client.client(url,{},"GET",force_raise=True,enable_stream=False)
if response_order_status.status_code == 200:
while response_order_status.json()["status"] != "completed" and "tasks" not in response_order_status.json():
time.sleep(1)
response_order_status=self.client.client(url,params,"GET",force_raise=True,enable_stream=False)
for elem in tqdm(response_order_status.json()["tasks"]):
url=elem[ "download"]["url"]
response_download=self.client.client(url,{},"GET",force_raise=False,enable_stream=False)
if response_download.status_code != 200:
print(AdamApiMessage(response_download.json()))
else:
outname=re.findall('filename="(.+)"', response_download.headers['content-disposition'])[0]
with open(os.path.join(output_dir,outname), 'wb' ) as f:
f.write( response_download.content )
return AdamApiMessage(response_order_status.json())
else:
return AdamApiMessage(response_order_submit.json())
else:
raise AdamApiError(response_order_submit.json())
def checkParams(self, request,asynchronous, compress,rest,filters,options,kwargs):
params={}
fname=None
op_kwargs = kwargs.copy()
#manage outDir
if "outputDir" in op_kwargs:
del(op_kwargs["outputDir"])
#manage filters
params["filters"] = {}
filt = {}
for(key,value)in filters.items():
if key == "geometry":
if isinstance(value,str):
filt[key]=value
else:
filt[key]=json.dumps(value)
else:
filt[key]=value
#manage options
opt = {}
for(key,value)in options.items():
opt[key]=value
for (key,value) in op_kwargs.items():
params[key] = value
#check date
if "startDate" in filt and not self._checkDate(filt["startDate"]):
raise AdamApiError("Parameter Error. Invalid date format [%Y-%m-%d,%Y-%m-%dT%H:%M:%SZ,%Y-%m-%dT%H:%M:%S]")
if "endDate" in filt and not self._checkDate(filt["endDate"]):
raise AdamApiError("Parameter Error. Invalid date format [%Y-%m-%d,%Y-%m-%dT%H:%M:%SZ,%Y-%m-%dT%H:%M:%S]")
if "startDate" in filt and "endDate" in filt:
if filt["startDate"] > filt["endDate"]:
raise AdamApiError("Parameter Error. startDate > endDate")
#check Getfile
if "format" in opt and request == "GetFile":
raise AdamApiError("invalid option for GetFile request. remove format")
params["options"] = json.dumps(opt)
params["filters"] = json.dumps(filt)
params["client"] = "adamapi"
params["rest"] = rest
params["compress"] = compress
params["request"] = request
params["asynchronous"] = asynchronous
return params,fname
def _checkDate(self,date):
test=False
pattern=[
"%Y-%m-%d",
"%Y-%m-%dT%H:%M:%SZ",
"%Y-%m-%dT%H:%M:%S"
]
for p in pattern:
try:
datetime.strptime(date,p)
test=True
except:
pass
return test
def _checkDir(selfi,dirname):
try:
os.makedirs( dirname )
except OSError as ose:
if ose.errno!=errno.EEXIST:
raise AdamApiError( ose )
"""
Copyright (c) 2022 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from datetime import datetime
import os
import logging
import json
logger=logging.getLogger('adamapi')
from . import AdamApiError
class Search():
def __init__(self,client):
self.LOG=logger
self.client=client
def getProducts(self,datasetId,startIndex=0,maxRecords=10,**kwargs):
"""
Product Catalogue Search
@ datasetId, the dataseId ,required
@ startDate, search start date (%Y-%m-%d)
@ endDate, search end date (%Y-%m-%d)
@ maxRecords, number of result showed
@ startIndex, index of the first result to start showin
"""
params={}
url=os.path.join( 'apis','v2','opensearch',datasetId.split(":",1)[0],'records')
params['datasetId']=datasetId.split(":",1)[1]
params["client"]="adamapi"
for par in kwargs:
if par == 'geometry':
if type(kwargs[par]) is str:
params[par] = kwargs[par]
elif type(kwargs[par]) is dict:
params[par] = json.dumps(kwargs[par])
elif par == 'startDate' and isinstance( kwargs[par], datetime ):
params[ 'startDate' ] = kwargs[par].strftime( '%Y-%m-%dT%H:%M:%SZ' )
elif par == 'endDate' and isinstance( kwargs[par], datetime ):
params[ 'endDate' ] = kwargs[par].strftime( '%Y-%m-%dT%H:%M:%SZ' )
else:
params[par]=kwargs[par]
params["page"]=startIndex
params["items"]=maxRecords
if 'geometry' in kwargs:
self.LOG.info(params)
response=self.client.client(url,params,"POST").json()
else:
response=self.client.client(url,params,"GET").json()
if 'errors' in response:
raise AdamApiError(response['errors'])
else:
return response
+337
-301
Metadata-Version: 2.1
Name: adamapi
Version: 2.0.11
Version: 2.1.0
Summary: Python Adam API

@@ -8,303 +8,3 @@ Home-page: https://git.services.meeo.it/das/adamapi

Author-email: info@meeo.it
License: UNKNOWN
Description: # Installation
### Versioning
1. adamapi==1.0.1 , This package works only with ADAMCORE 1.
2. adamapi==2.0.11, This pachage works only with ADAMCORE 2.
## Requirements
```bash
sudo apt-get install python3-venv python3-gdal gdal-bin
```
## Install with pip
```bash
VENVNAME="adamapi"
python3 -m venv "${VENVNAME}"
PYTHONVERSION=$(ls ${VENVNAME}/lib/)
source "${VENVNAME}/bin/activate";
python3 -m pip install --upgrade pip;
pip install adamapi==2.0.1r1
ln -s "/usr/lib/python3/dist-packages/osgeo" "${VENVNAME}/lib/${PYTHONVERSION}/site-packages/osgeo"
```
# API DEFINITIONS
This document briefly describes the ADMAPI functionalities.<br>
The complete and interactive documentation is provided through a jupyter notebook *(LINK to notebook TBP)*.<br>
The ADAMAPI library is divided in 4 modules:
1. Auth --> the authorization module
2. Datasets --> to get the list of datasets
3. Search --> to get the lists of products, including associated metadata (e.g. geometry, cloud cover, orbit, tile, ...)
4. GetData --> to retrieve the product(s), including options to subset in space and time
## 1 - Auth
This module takes care of user authentication and authorization.<br>
Without instancing an object of this module other components don't work.<br>
Auth module is based on the ADAMAPI_KEY, a key that uniquelly identifies the user.
**Class contructor and parameters**
```python
from adamapi import Auth
a = Auth()
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
**Public methods and parameters**
* **.setKey()** --> To setup the ADAMAPI_KEY<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The ADAMAPI_KEY |
* **.setAdamCore()** --> To setup the url of the ADAM-CORE endpoint<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The url like https://test.adamplatform.eu |
* **.authorize()** --> to instanciate an auth object<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
* **.getAuthToken()** --> to get the authorization token<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
### 1.1 - ADAMAPI_KEY retrieval
To get the ADAMAPI_KEY, you need to access your ADAM portal and:<br>
1. Select the "user icon" on the top right
2. Expand / click the "USERNAME"
3. Click on the "Api Key" to display your key
<br>
*Command-line ADAMAPI_KEY retrieval TBP*
### 1.2 - ADAMAPI_KEY setup
There are three methods to setup the ADAMAPI_KEY and the ADAM-CORE instance:
1. use the method setKey() and setAdamCore()
```python
from adamapi import Auth
a = Auth()
a.setKey('<ADAMAPI_KEY>')
a.setAdamCore('https://test.adamplatform.eu')
```
2. Export two envars like
```bash
#open a Terminal and type:
export ADAMAPI_KEY='<ADAMAPI_KEY>'
export ADAMAPI_URL='https://test.adamplatform.eu'
```
3. create a file called **.adamapirc** in the user home directory with the following content
```text
key=<ADAMAPI_KEY>
url=https://test.adamplatform.eu
```
### 1.3 - Examples
After ADAMAPI_KEY has been set up, an auth instance can be created with:
```python
from adamapi import Auth
a = Auth()
a.authorize()
```
After authorize method you can retrive your autho token:
```python
from adamapi import Auth
a = Auth()
a.authorize()
a.getAuthToken()
```
## 2 - Datasets
This module provides datasets discovery functionality.
**Class contructor and parameters**
```python
from adamapi import Datasets
datasets = Datasets( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in the previous section |
**Public methods and parameters**
* **.getDatasets()** --> To retrieve datasets list <br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | False | str | | The datasetId. |
| page | False | numeric | 0 | Indicats a specific page |
| maxRecords | False | numeric | 10 | Max number of results in output. |
This .getDatasets() function can be used to retrive additional filters which are described in the key **filtersEnabled** (if exists).
### 2.1 Examples
This module can be used in 2 different ways.
1. To list all available datasets:
```python
datasets = Datasets(a)
print(datasets.getDatasets())
```
2. To get detailed metadata about a specific dataset
```python
datasets = Datasets(a)
print( datasets.getDatasets( '{{ID:DATASET}}' , page=0 , maxRecords=10 ) )
```
3. To get filtersEnabled. To use this additional filters see first example in Search section.
```python
datasets = Datasets(a)
out=datasets.getDatasets("{{ID:DATASET}}")
print(out["filtersEnabled"])
```
## 3 - Search
This module provides discovery functionality through the products available on the ADAM instance.
**Class contructor and parameters**
```python
from adamapi import Search
search = Search( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in section 1-Auth |
**Public methods and parameters**
* **.getProducts()** --> To retrieve datasets list and metadata<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId. |
| maxRecords | False | int | 10 | number of records |
| startIndex | False | int | 0 | starting record index |
| startDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the start date |
| endDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the end date |
| geometry | True | str or geojson | | GeoJson geometry,[geojson format](https://tools.ietf.org/html/rfc7946) [appendix](#geometry)|
### 3.1 Examples
1. Example1:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0,platform="{{VALUE}}")
```
2. Example2:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0)
```
## 4 - getData
This module provides data access of raster, spatial subset and timeseries.
**Class contructor and parameters**
```python
from adamapi import GetData
data=GetData(a)
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth Instance | | The ADAMAPI authorized instance obtained in the section 1-Auth |
**Public methods and parameters**
* **.getData()** --> To retrieve a product<br>
Parameters to retrive a product:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId |
| 1 | True | str | | The productId |
| outputFname | False | str | "adamapiresults/datasetId" | absolute filename or relative filename without extension. If not set, the retrived product is saved in "adamapiresults/datasetId.tif" |
Parameters to retrive a subset or a timeseries:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId |
| 1 | True | str | | startDate |
| 2 | True | str | | endDate |
| 3 | False | boolean | False | asyncronous management for subset and timeseries order |
| geometry | True | str or geojson | | GeoJson geometry, if the geometry is a Point the api return a timeseries,[geojson format](https://tools.ietf.org/html/rfc7946) [appendix](#geometry)|
| outputFname | False | str | "adamapiresults/datasetId" | absolute filename without extension. If not set, the retrived product is saved in "adamapiresults/datasetId" |
### 4.1 Examples
```python
data=GetData(a)
#to retrive a raster
image=data.getData('{{ID:DATASET}}',productId='{{productId}}')
#or image=data.getData('{{ID:DATASET}}',productId='{{productId}}',outputFname="adamapi/test_get_data")
#to retrive a subset
image=data.getData(datasetId, startDate, endDate, geometry = '{"type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [43.916666667, 15.416666667 ], [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ]]]}')
#to retrive a timeseries
px_series=data.getData(datasetId, startDate, endDate, geometry = '{"type": "Point","coordinates":[43.916666667, 15.716666667]}')
#asyncronous management
image=data.getData(datasetId, startDate, endDate, asyncron= True,geometry = '{"type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [43.916666667, 15.416666667 ], [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ]]]}')
#check order status
- get order info:
image.pk -> order key
image.status -> order status
image.location -> order location when status is completed
image=data.getData(datasetId, asyncron= True,pk=image.pk)
```
## Appendix
### Geometry
```python
#This geometry will return all the results it has intersected within it
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [ 43.916666667, 15.416666667 ] , [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ] ] ] }
```
```python
#This geometry will return all the results it has intersected on its outside
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.84986877441406,15.925676536359038 ], [ 44.6539306640625,15.950766025306109 ],[ 44.681396484375,15.194084972583916 ], [ 43.8189697265625,15.20998780073036 ], [ 43.84986877441406,15.925676536359038 ] ] ] }
```
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.8
Classifier: License :: OSI Approved :: MIT License

@@ -314,1 +14,337 @@ Classifier: Operating System :: Unix

Description-Content-Type: text/markdown
License-File: LICENSE
# Installation
### Versioning
1. adamapi==2.0.11 , This package works only with ADAMCORE 1.
2. adamapi==2.1.0, This pachage works only with ADAMCORE 2.
## Requirements
```bash
sudo apt-get install python3-venv python3-gdal gdal-bin
```
## Install with pip
```bash
VENVNAME="adamapi"
python3 -m venv "${VENVNAME}"
source "${VENVNAME}/bin/activate";
python3 -m pip install --upgrade pip;
pip install adamapi
ln -s "/usr/lib/python3/dist-packages/osgeo" "${VENVNAME}/lib/python3.8/site-packages/osgeo"
```
# API DEFINITIONS
This document briefly describes the ADMAPI functionalities.<br>
The ADAMAPI library is divided in 4 modules:
1. Auth --> the authorization module
2. Datasets --> to get the list of datasets
3. Search --> to get the lists of products, including associated metadata (e.g. geometry, cloud cover, orbit, tile, ...)
4. GetData --> to retrieve the product(s), including options to subset in space and time in the native data granularity and reduced processing capacity
## 1 - Auth
This module takes care of user authentication and authorization.<br>
Without instancing an object of this module other components don't work.<br>
Auth module is based on the ADAMAPI_KEY, a key that uniquelly identifies the user.
**Class contructor and parameters**
```python
from adamapi import Auth
a = Auth()
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
**Public methods and parameters**
* **.setKey()** --> To setup the ADAMAPI_KEY<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The ADAMAPI_KEY |
* **.setAdamCore()** --> To setup the url of the ADAM-CORE endpoint<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The url like https://test.adamplatform.eu |
* **.authorize()** --> to instanciate an auth object<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
* **.getAuthToken()** --> to get the authorization token<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
### 1.1 - ADAMAPI_KEY retrieval
To get the ADAMAPI_KEY, you need to access your ADAM portal and:<br>
1. Select the "user icon" on the top right
2. Expand / click the "USERNAME"
3. Click on the "Api Key" to display your key
<br>
*Command-line ADAMAPI_KEY retrieval TBP*
### 1.2 - ADAMAPI_KEY setup
There are three methods to setup the ADAMAPI_KEY and the ADAM-CORE instance:
1. use the method setKey() and setAdamCore()
```python
from adamapi import Auth
a = Auth()
a.setKey('<ADAMAPI_KEY>')
a.setAdamCore('https://test.adamplatform.eu')
```
2. Export two envars like
```bash
#open a Terminal and type:
export ADAMAPI_KEY='<ADAMAPI_KEY>'
export ADAMAPI_URL='https://test.adamplatform.eu'
```
3. create a file called **.adamapirc** in the user home directory with the following content
```text
key=<ADAMAPI_KEY>
url=https://test.adamplatform.eu
```
### 1.3 - Examples
After ADAMAPI_KEY has been set up, an auth instance can be created with:
```python
from adamapi import Auth
a = Auth()
a.authorize()
```
After authorize method you can retrive your autho token:
```python
from adamapi import Auth
a = Auth()
a.authorize()
a.getAuthToken()
```
## 2 - Datasets
This module provides datasets discovery functionality.
**Class contructor and parameters**
```python
from adamapi import Datasets
datasets = Datasets( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in the previous section |
**Public methods and parameters**
* **.getDatasets()** --> To retrieve datasets list <br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | False | str | | The datasetId. |
| page | False | numeric | 0 | Indicats a specific page |
| maxRecords | False | numeric | 10 | Max number of results in output. |
This .getDatasets() function can be used to retrive additional filters which are described in the key **filtersEnabled** (if exists).
### 2.1 Examples
This module can be used in 2 different ways.
1. To list all available datasets:
```python
datasets = Datasets(a)
print(datasets.getDatasets())
```
2. To get detailed metadata about a specific dataset
```python
datasets = Datasets(a)
print( datasets.getDatasets( '{{ID:DATASET}}' , page=0 , maxRecords=10 ) )
```
3. To get filtersEnabled. To use this additional filters see first example in Search section.
```python
datasets = Datasets(a)
out=datasets.getDatasets("{{ID:DATASET}}")
print(out["filtersEnabled"])
```
## 3 - Search
This module provides discovery functionality through the products available on the ADAM instance.
**Class contructor and parameters**
```python
from adamapi import Search
search = Search( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in section 1-Auth |
**Public methods and parameters**
* **.getProducts()** --> To retrieve datasets list and metadata<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId. |
| maxRecords | False | int | 10 | number of records |
| startIndex | False | int | 0 | starting record index |
| startDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the start date |
| endDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the end date |
| geometry | True | str or geojson | | GeoJson geometry,[geojson format](https://tools.ietf.org/html/rfc7946) [appendix](#geometry)|
### 3.1 Examples
1. Example1:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0,platform="{{VALUE}}")
```
2. Example2:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0)
```
## 4 - GetData
This module provides data access of raster, spatial subset, timeseries in the native data granularity and reduced processing capacity.
**Class contructor and parameters**
```python
from adamapi import GetData
data=GetData(a)
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth Instance | | The ADAMAPI authorized instance obtained in the section 1-Auth |
**Public methods and parameters**
* **.getData()** --> To retrieve a specific product or a dataset in its native granularity, to get a subset of it, to perform a timeseries or to exec simple processing <br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId |
| 1 | True | str | GetFile | request type. available values: GetFile,GetSubset, GetTimeseries and GetProcessing |
| asynchronous | False | boolean | False | rappesents how the request will be performed |
| compress | False | boolean | False | return a zip file |
| rest | False | boolean | True | perform RESTful order ignoring explorer state on the server and equalization configured using the explorer gui |
| filters | True | json | {} | json object with filters parameter. startDate and endDate are required inside it |
| options | False | json | {} | request option |
| outputDir | False | str | `adamapiresults/` | set a different download directory inside `adamapiresult/` main directory |
### 4.1 Examples
```python
data=GetData(a)
#to retrive a specific product
image = data.getData('{{ID:DATASET}}',"GetFile",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"productId":'{{PRODUCTID}}'},outputDir='{{OUTPUT_DIR}}')
#to retrieve a dataset in its native granularity
data=GetData(self.a)
image = data.getData('{{ID:DATASET}}',"GetFile",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},outputDir='{{OUTPUT_DIR}}')
```
For the GetSubset,GetTimeseries and GetProcessing requests you need to add the `options` parameter with these constraints : [output formats](#output-formats) and [functions](#processing-function)(only for processing request)
```python
#subset example
image = data.getData('{{ID:DATASET}}',"GetSubset",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#timeseries example
image = data.getData('{{ID:DATASET}}',"GetTimeseries",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#processing example
image = data.getData('{{ID:DATASET}}',"GetProcessing",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMAT}}',"function":'{{FUNCTION}}'},outputDir='{{OUTPUT_DIR}}')
```
### 4.3 Asyncronous Example
```python
#1. execute the request
image = data.getData('{{ID:DATASET}}',"GetSubset",asynchronous=False,compress=False,rest=False,filters={"startDate":'{{STARTDATE}}',"endDate":'{{ENDDATE}}',"geometry":'{{GEOMETRY}}'},options={"format":'{{FORMATS}}'},outputDir='{{OUTPUT_DIR}}')
#2. check the status
stat=data.getData(datasetId,"GetSubset",asynchronous=True,id=str(image.pk))
while stat.status != "completed":
time.sleep(1)
stat=data.getData(datasetId,"GetSubset",asynchronous=True,id=str(image.pk))
#3. download the zip,unzip it and remove the zip (optional)
for res in stat.list:
if res["status"] == "failed":
print(res["exit_code"])
else:
r=self.a.client(res["download"]["url"],{},"GET")
with open(str(res["download"]["url"].split("/")[4])+"_"+str(res["download"]["url"].split("/")[5]), 'wb' ) as f:
f.write( r.content )
```
# Appendix 1 - Data format
## date and date+time
Supported string date/date+time format are:
* '%Y-%m-%dT%H:%M:%S',
* '%Y-%m-%dT%H:%M:%SZ',
* '%Y-%m-%d'
### GeoJson
Geometry have to follow the latest geojson standard [rfc7946](https://tools.ietf.org/html/rfc7946)<br>
In particular Polygons and MultiPolygons should follow the right-hand rule<br>
### Geometry
```python
#This geometry will return all the results it has intersected within it
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [ 43.916666667, 15.416666667 ] , [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ] ] ] }
```
```python
#This geometry will return all the results it has intersected on its outside
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.84986877441406,15.925676536359038 ], [ 44.6539306640625,15.950766025306109 ],[ 44.681396484375,15.194084972583916 ], [ 43.8189697265625,15.20998780073036 ], [ 43.84986877441406,15.925676536359038 ] ] ] }
```
### Output Formats
| request | output format |
| ---- | ---- |
| GetFile | - |
| GetSubset | tiff,png |
| GetTimeseries | json,csv |
| GetProcessing | tiff,png |
### Processing Function
| type | description |
| ---- | ---- |
| average | execute the average from the products |
| overlap | execute the products overlap without any specific strategy |
| mosterecent | puts on the top the most recent product |
| leastrecent | puts on top the least recent product |
| minvalue | for each pixel, puts on top the minimum value of the pixel |
| maxvalue | for each pixel, puts on top the maximum value of the pixel |
"""
Copyright (c) 2020 MEEO s.r.l.
Copyright (c) 2022 MEEO s.r.l.

@@ -26,3 +26,3 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

with open("../doc/api_definitions_no_image.md","r") as fh:
with open("README.md","r") as fh:
long_description=fh.read()

@@ -32,3 +32,3 @@

name="adamapi",
version="2.0.11",
version="2.1.0",
author="MEEO s.r.l.",

@@ -40,11 +40,23 @@ author_email="info@meeo.it",

url="https://git.services.meeo.it/das/adamapi",
packages=['adamapi'],
packages=setuptools.find_packages(where="src"),
package_dir={"":"src"},
install_requires=[
'requests >= 2.22.0',
'imageio'
'imageio == 2.9.0',
'tqdm == 4.62.3',
'numpy == 1.21.2',
'python-dateutil == 2.8.2',
'matplotlib == 3.4.3',
"certifi == 2021.5.30",
"charset-normalizer == 2.0.6",
"cycler == 0.10.0",
"idna == 3.2",
"kiwisolver == 1.3.2",
"Pillow == 8.3.2",
"pyparsing == 2.4.7",
"six == 1.16.0",
"urllib3 ==1.26.7"
],
classifiers=[
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.8",
"License :: OSI Approved :: MIT License",

@@ -55,3 +67,1 @@ "Operating System :: Unix",

)
Metadata-Version: 2.1
Name: adamapi
Version: 2.0.11
Summary: Python Adam API
Home-page: https://git.services.meeo.it/das/adamapi
Author: MEEO s.r.l.
Author-email: info@meeo.it
License: UNKNOWN
Description: # Installation
### Versioning
1. adamapi==1.0.1 , This package works only with ADAMCORE 1.
2. adamapi==2.0.11, This pachage works only with ADAMCORE 2.
## Requirements
```bash
sudo apt-get install python3-venv python3-gdal gdal-bin
```
## Install with pip
```bash
VENVNAME="adamapi"
python3 -m venv "${VENVNAME}"
PYTHONVERSION=$(ls ${VENVNAME}/lib/)
source "${VENVNAME}/bin/activate";
python3 -m pip install --upgrade pip;
pip install adamapi==2.0.1r1
ln -s "/usr/lib/python3/dist-packages/osgeo" "${VENVNAME}/lib/${PYTHONVERSION}/site-packages/osgeo"
```
# API DEFINITIONS
This document briefly describes the ADMAPI functionalities.<br>
The complete and interactive documentation is provided through a jupyter notebook *(LINK to notebook TBP)*.<br>
The ADAMAPI library is divided in 4 modules:
1. Auth --> the authorization module
2. Datasets --> to get the list of datasets
3. Search --> to get the lists of products, including associated metadata (e.g. geometry, cloud cover, orbit, tile, ...)
4. GetData --> to retrieve the product(s), including options to subset in space and time
## 1 - Auth
This module takes care of user authentication and authorization.<br>
Without instancing an object of this module other components don't work.<br>
Auth module is based on the ADAMAPI_KEY, a key that uniquelly identifies the user.
**Class contructor and parameters**
```python
from adamapi import Auth
a = Auth()
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
**Public methods and parameters**
* **.setKey()** --> To setup the ADAMAPI_KEY<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The ADAMAPI_KEY |
* **.setAdamCore()** --> To setup the url of the ADAM-CORE endpoint<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The url like https://test.adamplatform.eu |
* **.authorize()** --> to instanciate an auth object<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
* **.getAuthToken()** --> to get the authorization token<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| | | | | |
### 1.1 - ADAMAPI_KEY retrieval
To get the ADAMAPI_KEY, you need to access your ADAM portal and:<br>
1. Select the "user icon" on the top right
2. Expand / click the "USERNAME"
3. Click on the "Api Key" to display your key
<br>
*Command-line ADAMAPI_KEY retrieval TBP*
### 1.2 - ADAMAPI_KEY setup
There are three methods to setup the ADAMAPI_KEY and the ADAM-CORE instance:
1. use the method setKey() and setAdamCore()
```python
from adamapi import Auth
a = Auth()
a.setKey('<ADAMAPI_KEY>')
a.setAdamCore('https://test.adamplatform.eu')
```
2. Export two envars like
```bash
#open a Terminal and type:
export ADAMAPI_KEY='<ADAMAPI_KEY>'
export ADAMAPI_URL='https://test.adamplatform.eu'
```
3. create a file called **.adamapirc** in the user home directory with the following content
```text
key=<ADAMAPI_KEY>
url=https://test.adamplatform.eu
```
### 1.3 - Examples
After ADAMAPI_KEY has been set up, an auth instance can be created with:
```python
from adamapi import Auth
a = Auth()
a.authorize()
```
After authorize method you can retrive your autho token:
```python
from adamapi import Auth
a = Auth()
a.authorize()
a.getAuthToken()
```
## 2 - Datasets
This module provides datasets discovery functionality.
**Class contructor and parameters**
```python
from adamapi import Datasets
datasets = Datasets( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in the previous section |
**Public methods and parameters**
* **.getDatasets()** --> To retrieve datasets list <br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | False | str | | The datasetId. |
| page | False | numeric | 0 | Indicats a specific page |
| maxRecords | False | numeric | 10 | Max number of results in output. |
This .getDatasets() function can be used to retrive additional filters which are described in the key **filtersEnabled** (if exists).
### 2.1 Examples
This module can be used in 2 different ways.
1. To list all available datasets:
```python
datasets = Datasets(a)
print(datasets.getDatasets())
```
2. To get detailed metadata about a specific dataset
```python
datasets = Datasets(a)
print( datasets.getDatasets( '{{ID:DATASET}}' , page=0 , maxRecords=10 ) )
```
3. To get filtersEnabled. To use this additional filters see first example in Search section.
```python
datasets = Datasets(a)
out=datasets.getDatasets("{{ID:DATASET}}")
print(out["filtersEnabled"])
```
## 3 - Search
This module provides discovery functionality through the products available on the ADAM instance.
**Class contructor and parameters**
```python
from adamapi import Search
search = Search( a )
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth instance | | The ADAMAPI authorized instance obtained in section 1-Auth |
**Public methods and parameters**
* **.getProducts()** --> To retrieve datasets list and metadata<br>
Parameters:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId. |
| maxRecords | False | int | 10 | number of records |
| startIndex | False | int | 0 | starting record index |
| startDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the start date |
| endDate | False | str or [datetime](https://docs.python.org/3/library/datetime.html) | | the end date |
| geometry | True | str or geojson | | GeoJson geometry,[geojson format](https://tools.ietf.org/html/rfc7946) [appendix](#geometry)|
### 3.1 Examples
1. Example1:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0,platform="{{VALUE}}")
```
2. Example2:
```python
search=Search(a)
mongo_search=search.getProducts('{{ID:DATASET}}',maxRecords=1,startIndex=0)
```
## 4 - getData
This module provides data access of raster, spatial subset and timeseries.
**Class contructor and parameters**
```python
from adamapi import GetData
data=GetData(a)
```
Parameters:<br>
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | Auth Instance | | The ADAMAPI authorized instance obtained in the section 1-Auth |
**Public methods and parameters**
* **.getData()** --> To retrieve a product<br>
Parameters to retrive a product:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId |
| 1 | True | str | | The productId |
| outputFname | False | str | "adamapiresults/datasetId" | absolute filename or relative filename without extension. If not set, the retrived product is saved in "adamapiresults/datasetId.tif" |
Parameters to retrive a subset or a timeseries:
| position/keyword | mandatory | type | default | description |
| ------ | ------ | ------ | ------ | ------ |
| 0 | True | str | | The datasetId |
| 1 | True | str | | startDate |
| 2 | True | str | | endDate |
| 3 | False | boolean | False | asyncronous management for subset and timeseries order |
| geometry | True | str or geojson | | GeoJson geometry, if the geometry is a Point the api return a timeseries,[geojson format](https://tools.ietf.org/html/rfc7946) [appendix](#geometry)|
| outputFname | False | str | "adamapiresults/datasetId" | absolute filename without extension. If not set, the retrived product is saved in "adamapiresults/datasetId" |
### 4.1 Examples
```python
data=GetData(a)
#to retrive a raster
image=data.getData('{{ID:DATASET}}',productId='{{productId}}')
#or image=data.getData('{{ID:DATASET}}',productId='{{productId}}',outputFname="adamapi/test_get_data")
#to retrive a subset
image=data.getData(datasetId, startDate, endDate, geometry = '{"type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [43.916666667, 15.416666667 ], [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ]]]}')
#to retrive a timeseries
px_series=data.getData(datasetId, startDate, endDate, geometry = '{"type": "Point","coordinates":[43.916666667, 15.716666667]}')
#asyncronous management
image=data.getData(datasetId, startDate, endDate, asyncron= True,geometry = '{"type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [43.916666667, 15.416666667 ], [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ]]]}')
#check order status
- get order info:
image.pk -> order key
image.status -> order status
image.location -> order location when status is completed
image=data.getData(datasetId, asyncron= True,pk=image.pk)
```
## Appendix
### Geometry
```python
#This geometry will return all the results it has intersected within it
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.916666667, 15.716666667 ], [ 43.916666667, 15.416666667 ] , [ 44.216666667, 15.416666667 ], [ 44.216666667, 15.716666667 ], [ 43.916666667, 15.716666667 ] ] ] }
```
```python
#This geometry will return all the results it has intersected on its outside
geometry = { "type": "Polygon", "coordinates": [ [ [ 43.84986877441406,15.925676536359038 ], [ 44.6539306640625,15.950766025306109 ],[ 44.681396484375,15.194084972583916 ], [ 43.8189697265625,15.20998780073036 ], [ 43.84986877441406,15.925676536359038 ] ] ] }
```
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.8
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Unix
Requires-Python: >=3.6
Description-Content-Type: text/markdown
imageio
requests>=2.22.0
setup.py
adamapi/__init__.py
adamapi/authorization.py
adamapi/datasets.py
adamapi/get_data.py
adamapi/search.py
adamapi.egg-info/PKG-INFO
adamapi.egg-info/SOURCES.txt
adamapi.egg-info/dependency_links.txt
adamapi.egg-info/requires.txt
adamapi.egg-info/top_level.txt
"""
Copyright (c) 2020 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
class AdamApiError( Exception ):
"""Base class for exceptions on the adamapi module."""
pass
class AdamApiMessage( Exception ):
"""Base class for adamapi mesage"""
def __init__(self,json):
self.pk=json["pk"] if "pk" in json else ""
self.status=json["status"] if "status" in json else ""
self.location = json["location"] if "location" in json else ""
self.error = json["error"] if "error" in json else ""
from . import authorization
from . import datasets
from . import get_data
from . import search
Auth = authorization.Auth
Datasets = datasets.Datasets
GetData = get_data.GetData
Search = search.Search
"""
Copyright (c) 2020 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import os
import requests
import re
import logging
from datetime import datetime,timedelta
logger = logging.getLogger( 'adamapi' )
from . import AdamApiError
class Auth():
def __init__( self, key=None, url=None ):
"""
Authorization class used to manage users credentials
"""
self.key = key
self.url = url
self.authorized = False
self.access_obj=None
self.lock=False
def authorize( self ):
"""
try to autorize the adamapi to the target adam instance
"""
#verify if key are valid
self._check()
url = os.path.join( self.url,'apis','v1','authorization', 'adamapi' )
headers={ 'Authorization': self.key }
r=requests.post( url,data={},headers=headers )
res = r.json()
if r.status_code !=200:
raise AdamApiError( res['title'] )
else:
logger.info( res )
self.authorized = True
self.access_obj= res
return res
def getAuthToken(self):
return {
"authorization_token" : self.access_obj["access_token"],
"expires_at" : self.access_obj["expires_at"]
}
def _check( self ):
"""
verify if the user key and the adam url are valid
"""
self.getKey()
self.getAdamCore()
if self.key is None:
raise AdamApiError( "key can not be None" )
if self.url is None:
raise AdamApiError( "url (adam endpoint) can not be None" )
def setKey( self, key ):
"""
set the user key
"""
self.key = key
def setAdamCore( self, url ):
"""
set the adam endpoint url
"""
self.url = url
def getKey( self ):
"""
key priority:
1 - use the key declared on this module
2 - use a key exported as envvars
3 - try to retrieve the key from $HOME/.adamapirc
"""
if self.key is not None:
pass
elif os.environ.get( 'ADAMAPI_KEY') is not None:
self.key = os.environ.get( 'ADAMAPI_KEY' )
logger.debug( 'Get key from envvar' )
else:
try:
self.key = self._getRc()[ 'key' ]
logger.debug( 'Get key from adamapirc' )
except:
None
if self.key is None: #again
logger.warning( "API key not specified" )
return self.key
def getAdamCore( self ):
"""
adam endpoint priority:
1 - use the url declared on this module
2 - use a url exported as envvars
3 - try to retrieve the url from $HOME/.adamapirc
"""
if self.url is not None:
pass
elif os.environ.get( 'ADAMAPI_URL') is not None:
self.url = os.environ.get( 'ADAMAPI_URL' )
logger.debug( 'Get url from envvar' )
else:
try:
self.url = self._getRc()[ 'url' ]
logger.debug( 'Get url from adamapirc' )
except:
None
if self.url is None: #again
logger.warning( "ADAM API endpoint not specified" )
return self.url
def _getRc( self ):
"""
check if ~/.adamapirc file exist ant try to extract url and key from it
"""
api_rc = os.environ.get( 'ADAMAPI_RC', os.path.expanduser( '~/.adamapirc' ) )
config_dict = {}
if os.path.isfile( api_rc ):
with open( api_rc ) as f:
for line in f.readlines():
line = line.strip()
if line.lstrip( '#' ) == line:
try:
key, val = line.split( '=', 1 )
config_dict[ key.strip() ] = val.strip()
except:
logger.warning( 'Invalid settings in "%s" - %s' %( api_rc, line ) )
return config_dict
def _checktokenExpire(self):
"""
check if token is expired
"""
if (datetime.strptime(self.access_obj['expires_at'],"%Y-%m-%dT%H:%M:%S.%fZ") - datetime.utcnow().replace(microsecond=0)) <= timedelta(minutes=15) :
return True
else:
return False
def _refreshToken(self):
"""
refresh tocken obj
"""
self.lock=True
params = {}
params["refresh_token"]=self.access_obj["refresh_token"]
self.access_obj = self.client(os.path.join( 'apis','v1', 'authorization', 'refresh' ), params, 'PUT').json()
self.lock=False
def client( self, query, params, request_type, authorization_required = True , force_raise = False ,enable_stream=False):
"""
The client method that perform the request appending the Authorization header
"""
#verify if the user already call the authorize method of the Auth instance
#if authorization_required and not self.authorized:
# self.authorize()
if not self.authorized and self.access_obj is not None :
raise AdamApiError("Unauthorized")
if not self.lock and self._checktokenExpire():
self._refreshToken()
#verify if the passed url already include the host or if the adamcore url have to be prepended
if re.match( r'^http[s]?://.+', query ):
url = query
else:
url = os.path.join( self.url, query )
if request_type not in [ 'GET', 'POST', 'PUT' ]:
raise AdamApiError( "Request type not supported" )
logger.debug( "%s request started", request_type )
if "\\" in url:
url = url.replace("\\","/")
if request_type == 'GET':
par = params.copy()
par["token"] = self.access_obj["access_token"]
r=requests.get( url, params=par ,stream=enable_stream)
elif request_type == 'POST':
par = params.copy()
par["token"] = self.access_obj["access_token"]
r=requests.post( url,data=par )
elif request_type == 'PUT':
r=requests.put( url,data=params )
logger.info(r.status_code)
if r.status_code in range(400,599):
if force_raise:
return r.raise_for_status()
else:
raise AdamApiError(r.json()['title'])
else:
return r
"""
Copyright (c) 2020 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import os
import logging
logger=logging.getLogger('adamapi')
from . import AdamApiError
class Datasets():
def __init__(self, client):
self.client = client
self.LOG = logger
def getDatasets(self,datasetId=None,**kwargs):
params={}
params["type"]="adamapi"
if datasetId:
url=os.path.join("apis","v2","datasets",datasetId.split(":")[0])
else:
url=os.path.join("apis","v2","datasets","list")
if 'page' in kwargs:
params['page']=kwargs['page']
else:
params['page']=0
if 'maxRecords' in kwargs:
params['maxRecords']=kwargs['maxRecords']
else:
params['maxRecords']=10
r = self.client.client( url, params, 'GET' )
self.LOG.info( 'Datasets request executed' )
response = r.json()
return response
#def getDatasets( self, datasetId=None,**kwargs ):
# """
# getDataset convention:
# 1. without parametes returns all datasets present over the adam endpoint;
# 2. with datasetId paramenter returns a specific description of this dataset
# @ {ID:datasetId}: the datasetId
# @ page: Indicats a specific page
# @ maxRecords: Max number of results in output
# """
# params={ 'datasetId':datasetId }
# params["type"]="adamapi"
# if 'page' in kwargs:
# params['page']=kwargs['page']
# else:
# params['page']=0
# if 'maxRecords' in kwargs:
# params['maxRecords']=kwargs['maxRecords']
# else:
# params['maxRecords']=10
# r = self.client.client( os.path.join( 'datasets', 'api', 'datasets' ), params, 'GET' )
# self.LOG.info( 'Datasets request executed' )
# response = r.json()
# if 'errors' in response:
# raise AdamApiError( response[ 'errors' ] )
# return response[ 'response' ]
"""
Copyright (c) 2020 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from datetime import timedelta, datetime, timezone
import os
import time
from osgeo import ogr
import imageio
import json
import requests
import errno
import csv
import logging
logger=logging.getLogger('adamapi')
from . import AdamApiError,AdamApiMessage
class GetData(object):
def __init__(self,client):
self.LOG=logger
self.client=client
def getData(self,datasetId,startDate=None,endDate=None,asyncron=False,**kwargs):
"""
Method to retrive:
1) the complete product
2) a geographic subset of the product
3) a timeseries on a point
@datasetId required
@startDate required for point 2 and 3, invalid for point 1
@endDate required for point 2 and 3, invalid for point 1
@outputFname optional
@geometry invalid in the case 1 but required in the case 2 and 3
@productid invalid in the case 2 and 3 but required in the case 1
"""
params,fname=self.checkParams(datasetId,startDate,endDate,kwargs)
if "pk" in params:
status = self._checkStatus(params["pk"],asyncron)
if status == "running":
return AdamApiMessage({"pk":params["pk"],"status":status})
elif status == "completed":
try:
url_download = os.path.join("apis","v2","chart","order",str(params["pk"]),"download")
response_download = self.client.client(url_download,{},"GET",force_raise=True,enable_stream=True)
response_download.raise_for_status()
except requests.exceptions.HTTPError as er:
url_download = os.path.join("apis","v2","subset","order",str(params["pk"]),"download")
response_download = self.client.client(url_download,{},"GET",force_raise=True,enable_stream=True)
except Exception as e:
self.LOG.exception("Un error occurd : %s"%(e))
raise AdamApiMessage( {"error":e} )
with open(fname,"wb") as f:
for chunk in response_download.iter_content(chunk_size=128):
f.write(chunk)
return AdamApiMessage({"pk":params["pk"],"status":status,"location":fname})
else:
return AdamApiMessage({"pk":params["pk"],"status":status})
if fname is None:
self.LOG.error("Unprocessable requests with productId and geometry. Execute a request with only once of two params")
raise AdamApiMessage( {"error":"Unprocessable requests with productId and geometry. Execute a request with only once of two params"})
self._checkDirFile(fname)
if "productId" in params:
url = os.path.join("apis","v2","opensearch",datasetId.split(":",1)[0],"records/",params["productId"]+"/","download")
method = "GET"
isorder=False
if "geometry" in params:
isorder=True
method = "POST"
try:
geom = ogr.CreateGeometryFromJson(params["geometry"])
except:
geom = ogr.CreateGeometryFromJson(json.dumps(params["geometry"]))
if geom.GetGeometryName() == "POINT":
url = os.path.join("apis","v2","chart","order",datasetId.split(":",1)[0]+"/")
is_timeseries=True
else:
is_timeseries=False
url = os.path.join("apis","v2","subset","order",datasetId.split(":",1)[0]+"/")
try:
response_order = self.client.client(url,params,method,force_raise = True,enable_stream=False)
response_order.raise_for_status()
if isorder:
if response_order.json()["status"] == "started":
if not asyncron:
status = self._checkStatus(response_order.json()["pk"],asyncron)
if status == "completed":
if is_timeseries:
url_download = os.path.join("apis","v2","chart","order",str(response_order.json()["pk"]),"download")
else:
url_download = os.path.join("apis","v2","subset","order",str(response_order.json()["pk"]),"download")
try:
response_download = self.client.client(url_download,{},"GET",force_raise=True,enable_stream=True)
response_download.raise_for_status()
with open(fname,"wb") as f:
for chunk in response_download.iter_content(chunk_size=128):
f.write(chunk)
except requests.exceptions.HTTPError as er:
raise AdamApiMessage( {"error":response_download.json()})
except Exception as e:
self.LOG.exception("Un error occurd : %s"%(e))
raise AdamApiMessage( {"error":e} )
else:
return AdamApiMessage(response_order.json())
if status == "failed":
self.LOG.error("Failed request")
raise AdamApiMessage({"status":status,"error":"Failed Request"})
else:
with open( fname, 'wb' ) as f:
f.write( response_order.content )
except requests.exceptions.HTTPError as er:
raise AdamApiMessage({"error":response_order.json()})
except Exception as e:
self.LOG.exception("Un error occurd : %s"%(e))
raise AdamApiMessage( {"error":e} )
return fname
def checkParams(self,datasetId,start_date,end_date,kwargs):
params={}
fname=None
op_kwargs = kwargs.copy()
if "productId" in kwargs and "geometry" in kwargs:
return params , None
if "outputFname" in kwargs and kwargs["outputFname"] is not None:
fname = kwargs["outputFname"]
del(op_kwargs["outputFname"])
else:
fname="adamapiresults/%s"%(datasetId.split(":")[-1])
for(key,value)in op_kwargs.items():
if key == "geometry":
if isinstance(value,str):
params[key]=value
else:
params[key]=json.dumps(value)
else:
params[key]=value
if "pk" in kwargs:
return params,fname
if "productId" not in kwargs:
if start_date > end_date:
raise AdamApiError("Invalid Temporal Filter: startDate > endDate")
params["start_date"]=start_date
params["end_date"]=end_date
params["type"]="adamapi"
return params,fname
def _checkStatus(self,oid,asyncron):
"""
wrap /status/order
"""
animation = "|/-\\"
idx = 0
params={}
url = os.path.join("apis","v2","subset","order",str(oid),"status")
if asyncron:
r = self.client.client(url,params,"GET",force_raise=True)
status = r.json()["status"]
else:
status = "running"
while status == "running":
time.sleep(2)
r = self.client.client(url,params,"GET",force_raise=True)
status = r.json()["status"]
if status == "running":
print(animation[idx % len(animation)], end="\r")
idx += 1
else:
break
return status
def _checkDirFile(self,filename):
dirname = os.path.dirname( filename )
if dirname.strip():
try:
os.makedirs( dirname )
except OSError as ose:
if ose.errno!=errno.EEXIST:
raise AdamApiError( ose )
"""
Copyright (c) 2020 MEEO s.r.l.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from datetime import datetime
import os
import logging
import json
logger=logging.getLogger('adamapi')
from . import AdamApiError
class Search():
def __init__(self,client):
self.LOG=logger
self.client=client
def getProducts(self,datasetId,startIndex=0,maxRecords=10,**kwargs):
"""
Product Catalogue Search
@ datasetId, the dataseId ,required
@ startDate, search start date (%Y-%m-%d)
@ endDate, search end date (%Y-%m-%d)
@ maxRecords, number of result showed
@ startIndex, index of the first result to start showin
"""
params={}
url=os.path.join( 'apis','v2','opensearch',datasetId.split(":",1)[0],'records')
params['datasetId']=datasetId.split(":",1)[1]
params["type"]="adamapi"
for par in kwargs:
if par == 'geometry':
if type(kwargs[par]) is str:
params[par] = kwargs[par]
elif type(kwargs[par]) is dict:
params[par] = json.dumps(kwargs[par])
elif par == 'startDate' and isinstance( kwargs[par], datetime ):
params[ 'startDate' ] = kwargs[par].strftime( '%Y-%m-%dT%H:%M:%SZ' )
elif par == 'endDate' and isinstance( kwargs[par], datetime ):
params[ 'endDate' ] = kwargs[par].strftime( '%Y-%m-%dT%H:%M:%SZ' )
else:
params[par]=kwargs[par]
params["page"]=startIndex
params["items"]=maxRecords
if 'geometry' in kwargs:
self.LOG.info(params)
response=self.client.client(url,params,"POST").json()
else:
response=self.client.client(url,params,"GET").json()
if 'errors' in response:
raise AdamApiError(response['errors'])
else:
return response