Skip to content

Commit

Permalink
Issue Open-EO#72: move "at least 0.4.0 api" version check to Connecti…
Browse files Browse the repository at this point in the history
…on constructor
  • Loading branch information
soxofaan committed Oct 24, 2019
1 parent 4467f4d commit f98f84e
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 83 deletions.
31 changes: 23 additions & 8 deletions openeo/capabilities.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from abc import ABC
from distutils.version import LooseVersion
from typing import Union


class Capabilities(ABC):
Expand Down Expand Up @@ -55,6 +56,7 @@ class CheckableVersion:
>>> v.at_least('1.10.2')
False
"""

def __init__(self, version):
self._version = LooseVersion(version)

Expand All @@ -64,14 +66,27 @@ def __str__(self):
def to_string(self):
return str(self)

def at_least(self, version):
return self._version >= LooseVersion(version)
@classmethod
def _to_loose_version(cls, version) -> LooseVersion:
if isinstance(version, cls):
return version._version
elif isinstance(version, str):
return LooseVersion(version)
else:
raise ValueError(version)

def at_least(self, version: Union[str, 'CheckableVersion']):
return self._version >= self._to_loose_version(version)

def above(self, version: Union[str, 'CheckableVersion']):
return self._version > self._to_loose_version(version)

def at_most(self, version: Union[str, 'CheckableVersion']):
return self._version <= self._to_loose_version(version)

def above(self, version):
return self._version > LooseVersion(version)
def below(self, version: Union[str, 'CheckableVersion']):
return self._version < self._to_loose_version(version)

def at_most(self, version):
return self._version <= LooseVersion(version)

def below(self, version):
return self._version < LooseVersion(version)
class ApiVersionException(RuntimeError):
pass
38 changes: 14 additions & 24 deletions openeo/rest/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from requests.auth import HTTPBasicAuth, AuthBase

import openeo
from openeo.capabilities import Capabilities
from openeo.capabilities import Capabilities, ApiVersionException, CheckableVersion
from openeo.imagecollection import CollectionMetadata
from openeo.rest.auth.auth import NullAuth, BearerAuth
from openeo.rest.imagecollectionclient import ImageCollectionClient
Expand Down Expand Up @@ -149,6 +149,8 @@ def put(self, path, headers: dict = None, data=None) -> Response:

class Connection(RestApiConnection):

_MINIMUM_API_VERSION = CheckableVersion("0.4.0")

def __init__(self, url, auth: AuthBase = None, session: requests.Session = None):
"""
Constructor of Connection, authenticates user.
Expand All @@ -157,6 +159,12 @@ def __init__(self, url, auth: AuthBase = None, session: requests.Session = None)
super().__init__(root_url=url, auth=auth, session=session)
self._cached_capabilities = None

# Initial API version check.
if self._api_version.below(self._MINIMUM_API_VERSION):
raise ApiVersionException("OpenEO API version should be at least {m!s}, but got {v!s}".format(
m=self._MINIMUM_API_VERSION, v= self._api_version)
)

def authenticate_basic(self, username: str, password: str) -> 'Connection':
"""
Authenticate a user to the backend using basic username and password.
Expand Down Expand Up @@ -223,8 +231,7 @@ def list_collection_ids(self) -> List[str]:
Get list of all collection ids
:return: list of collection ids
"""
field = 'id' if self._api_version.at_least('0.4.0') else 'name'
return [collection[field] for collection in self.list_collections() if field in collection]
return [collection['id'] for collection in self.list_collections() if 'id' in collection]

def capabilities(self) -> 'Capabilities':
"""
Expand Down Expand Up @@ -300,7 +307,7 @@ def list_processgraphs(self, process_graph):
raise NotImplementedError()

@property
def _api_version(self):
def _api_version(self) -> CheckableVersion:
return self.capabilities().api_version_check

def load_collection(self, collection_id: str) -> ImageCollectionClient:
Expand Down Expand Up @@ -367,16 +374,9 @@ def download(self, graph, outputfile, format_options):
:param format_options: formating options
:return: job_id: String
"""
path = "/preview"
request = {
"process_graph": graph
}
if self._api_version.at_least('0.4.0'):
path = "/result"
else:
request["output"] = format_options
request = {"process_graph": graph}

download_url = self.build_url(path)
download_url = self.build_url("/result")

r = self.post(download_url, json=request, stream=True, timeout=1000)
with open(outputfile, 'wb') as f:
Expand All @@ -392,10 +392,7 @@ def execute(self, process_graph, output_format, output_parameters=None, budget=N
:return: job_id: String
"""
# TODO: add output_format to execution
path = "/preview"
if self._api_version.at_least('0.4.0'):
path = "/result"
response = self.post(path, process_graph)
response = self.post(path="/result", json=process_graph)
return self.parse_json_response(response)

def create_job(self, process_graph:Dict, output_format:str=None, output_parameters:Dict={},
Expand All @@ -420,16 +417,9 @@ def create_job(self, process_graph:Dict, output_format:str=None, output_paramete
"budget": budget
}

if not self._api_version.at_least('0.4.0'):
process_graph["output"] = {
"format": output_format,
"parameters": output_parameters
}

job_status = self.post("/jobs", process_graph)

job = None

if job_status.status_code == 201:
job_info = job_status.headers._store
if "openeo-identifier" in job_info:
Expand Down
3 changes: 0 additions & 3 deletions openeo/rest/imagecollectionclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ def load_collection(
:return:
"""
# TODO: rename function to load_collection for better similarity with corresponding process id?
assert session.capabilities().api_version_check.at_least('0.4.0')
builder = GraphBuilder()
process_id = 'load_collection'
arguments = {
Expand Down Expand Up @@ -80,8 +79,6 @@ def load_disk_collection(cls, session: 'Connection', file_format: str, glob_patt
:param options: options specific to the file format
:return: the data as an ImageCollection
"""
assert session.capabilities().api_version_check.at_least('0.4.0')

builder = GraphBuilder()

process_id = 'load_disk_data'
Expand Down
8 changes: 5 additions & 3 deletions tests/rest/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from openeo.rest.auth.auth import NullAuth, BearerAuth
from openeo.rest.connection import Connection, RestApiConnection, connect, OpenEoApiError

API_URL = "https://oeo.net/"
API_URL = "https://oeo.net"


@pytest.mark.parametrize(
Expand Down Expand Up @@ -101,25 +101,27 @@ def test_api_error_non_json(requests_mock):


def test_authenticate_basic(requests_mock):
requests_mock.get(API_URL, json={"api_version": "0.4.0"})
conn = Connection(API_URL)

def text_callback(request, context):
assert request.headers["Authorization"] == "Basic am9objpqMGhu"
return '{"access_token":"w3lc0m3"}'

requests_mock.get('https://oeo.net/credentials/basic', text=text_callback)
requests_mock.get(API_URL + '/credentials/basic', text=text_callback)

assert isinstance(conn.auth, NullAuth)
conn.authenticate_basic(username="john", password="j0hn")
assert isinstance(conn.auth, BearerAuth)
assert conn.auth.bearer == "w3lc0m3"


def test_authenticate_oidc(oidc_test_setup):
def test_authenticate_oidc(oidc_test_setup, requests_mock):
# see test/rest/conftest.py for `oidc_test_setup` fixture
client_id = "myclient"
oidc_discovery_url = "https://oeo.net/credentials/oidc"
state, webbrowser_open = oidc_test_setup(client_id=client_id, oidc_discovery_url=oidc_discovery_url)
requests_mock.get(API_URL, json={"api_version": "0.4.0"})

# With all this set up, kick off the openid connect flow
conn = Connection(API_URL)
Expand Down
2 changes: 1 addition & 1 deletion tests/rest/test_imagecollectionclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

@pytest.fixture
def session040(requests_mock):
requests_mock.get(API_URL + "/", json={"api_version": "0.4.0"})
session = openeo.connect(API_URL)
requests_mock.get(API_URL + "/", json={"version": "0.4.0"})
return session


Expand Down
10 changes: 5 additions & 5 deletions tests/test_bandmath.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
class TestBandMath(TestCase):

def test_basic(self, m):
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")
session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections/SENTINEL2_RADIOMETRY_10M", json={"product_id": "sentinel2_subset",
"bands": [{'band_id': 'B02'},
{'band_id': 'B04'},
Expand All @@ -32,11 +32,11 @@ def test_basic(self, m):
assert cube.band('B02').graph == expected_graph

def test_band_indexing(self, m):
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")
session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections/CGS_SENTINEL2_RADIOMETRY_V102_001", json={
"id": "CGS_SENTINEL2_RADIOMETRY_V102_001",
"properties": {
Expand All @@ -58,11 +58,11 @@ def test_band_indexing(self, m):

def test_evi(self,m):
# configuration phase: define username, endpoint, parameters?
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")
session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections", json={"collections": [{"product_id": "sentinel2_subset"}]})
m.get("http://localhost:8000/api/collections/SENTINEL2_RADIOMETRY_10M", json={"product_id": "sentinel2_subset",
"bands": [{'band_id': 'B02'},
Expand Down Expand Up @@ -94,11 +94,11 @@ def test_evi(self,m):

def test_ndvi_udf(self, m):
#configuration phase: define username, endpoint, parameters?
m.get("http://localhost:8000/api/", json={"version": "0.4.1"})
session = openeo.connect("http://localhost:8000/api")
session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.1"})
m.get("http://localhost:8000/api/collections", json={"collections": [{"product_id": "sentinel2_subset"}]})
m.get("http://localhost:8000/api/collections/SENTINEL2_RADIOMETRY_10M", json={"product_id": "sentinel2_subset",
"bands": [{'band_id': 'B0'},
Expand Down Expand Up @@ -154,9 +154,9 @@ def test_ndvi_udf(self, m):

def test_ndvi_udf_0_4_0(self, m):
#configuration phase: define username, endpoint, parameters?
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections", json={"collections": [{"product_id": "sentinel2_subset"}]})
m.get("http://localhost:8000/api/collections/SENTINEL2_RADIOMETRY_10M", json={"product_id": "sentinel2_subset",
"bands": [{'band_id': 'B0'},
Expand Down
2 changes: 1 addition & 1 deletion tests/test_batch_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
class TestBatchJobs(TestCase):

def test_create_job(self,m):
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")
#session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections", json={"collections": [{"product_id": "sentinel2_subset"}]})
m.get("http://localhost:8000/api/collections/SENTINEL2_RADIOMETRY_10M", json={"product_id": "sentinel2_subset",
"bands": [{'band_id': 'B02'},
Expand Down
5 changes: 5 additions & 0 deletions tests/test_capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ def test_checkable_version():
assert v.at_most('1.2.2b') is False
assert v.at_most('1.2') is False
assert v.at_most('1.10')

assert v.above(CheckableVersion('1.2'))
assert v.at_least(CheckableVersion('1.2.3a')) is False
assert v.at_most(CheckableVersion('1.02.03'))

6 changes: 3 additions & 3 deletions tests/test_logical_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ class TestLogicalOps(TestCase):

def test_not_equal(self, m):
# configuration phase: define username, endpoint, parameters?
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")
session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections", json={"collections": [{"product_id": "sentinel2_subset"}]})
m.get("http://localhost:8000/api/collections/SENTINEL2_SCF", json={
"product_id": "sentinel2_subset",
Expand All @@ -42,11 +42,11 @@ def test_not_equal(self, m):
assert actual_graph == expected_graph

def test_or(self, m):
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")
session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections", json={"collections": [{"product_id": "sentinel2_subset"}]})
m.get("http://localhost:8000/api/collections/SENTINEL2_SCF", json={
"product_id": "sentinel2_subset",
Expand All @@ -65,11 +65,11 @@ def test_or(self, m):
assert actual_graph == expected_graph

def test_and(self, m):
m.get("http://localhost:8000/api/", json={"api_version": "0.4.0"})
session = openeo.connect("http://localhost:8000/api")
session.post = MagicMock()
session.download = MagicMock()

m.get("http://localhost:8000/api/", json={"version": "0.4.0"})
m.get("http://localhost:8000/api/collections", json={"collections": [{"product_id": "sentinel2_subset"}]})
m.get("http://localhost:8000/api/collections/SENTINEL2_SCF", json={
"product_id": "sentinel2_subset",
Expand Down
Loading

0 comments on commit f98f84e

Please sign in to comment.