-
Notifications
You must be signed in to change notification settings - Fork 8
/
operations.py
224 lines (172 loc) · 6.27 KB
/
operations.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
from typing import Dict, Optional
from vortexasdk.api.id import ID
from vortexasdk.client import default_client
from vortexasdk.exceptions import InvalidAPIDataResponseException
from vortexasdk.logger import get_logger
from vortexasdk.search_response import SearchResponse
from vortexasdk.utils import filter_exact_match, PAGINATION_STRATEGIES
logger = get_logger(__name__)
class Reference:
"""Lookup Vortexa Reference Data using an entity ID."""
def __init__(self, resource):
"""
Init.
# Arguments
resource: The vortexa endpoint used for reference lookups.
"""
self._resource = resource
def reference(self, id: ID) -> Dict:
"""
Lookup reference data using ID.
# Arguments
id: ID of the entity we're looking up
# Returns
An entity matching the ID
# Examples
>>> Reference("/reference/geographies").reference(id='cfb8c4ef76585c3a37792b643791a0f4ff6d5656d5508927d8017319e21f2fca') # doctest: +SKIP
"""
logger.info(
f"Looking up {self.__class__.__name__} reference data with id: {id}"
)
data = default_client().get_reference(self._resource, id)
assert len(data) <= 1, InvalidAPIDataResponseException(
f"Server error: more than one record returned matching ID {id}"
)
try:
return data[0]
except IndexError:
return {}
class Search:
"""Search Vortexa Reference Data."""
def __init__(self, resource):
"""
Init.
# Arguments
resource: Appropriate search resource
"""
self._resource = resource
# This method has been renamed from `search` to `search_with_client` to avoid type signature
# issues with the `search` method in each endpoint class.
def search_with_client_base(
self,
exact_term_match: bool = None,
response_type: str = None,
headers: dict = None,
pagination_strategy: Optional[PAGINATION_STRATEGIES] = None,
**api_params,
) -> SearchResponse:
"""
Search Reference data filtering on `params`.
# Arguments
exact_term_match: Optional argument to filter names on exact matches
api_params: Search parameters to be passed on to the API
response_type: Optional type of the response - to handle endpoints which do not support paging
# Returns
Result of VortexaAPI call from hitting querying the `resource` endpoint filtering with `params`.
# Examples
>>> Search("/reference/vessels").search(term="DHT") # doctest: +SKIP
"""
logger.info(f"Searching {self.__class__.__name__}")
api_result = default_client().search_base(
self._resource,
response_type=response_type,
pagination_strategy=pagination_strategy,
headers=headers,
**api_params,
)
logger.debug(
f"{len(api_result)} results received from {self._resource}"
)
if exact_term_match:
logger.debug("Filtering results on exact term match")
return {
"reference": api_result["reference"],
"data": filter_exact_match(
api_params["term"], api_result["data"]
),
}
else:
return api_result
def search_with_client(
self,
exact_term_match: bool = None,
response_type: str = None,
headers: dict = None,
**api_params,
) -> SearchResponse:
return self.search_with_client_base(
exact_term_match,
response_type,
headers,
PAGINATION_STRATEGIES.OFFSET,
**api_params,
)
def search_with_client_with_search_after(
self,
exact_term_match: bool = None,
response_type: str = None,
headers: dict = None,
**api_params,
) -> SearchResponse:
return self.search_with_client_base(
exact_term_match,
response_type,
headers,
PAGINATION_STRATEGIES.SEARCH_AFTER,
**api_params,
)
class Record:
"""Lookup Vortexa Data using an record ID."""
def __init__(self, resource):
"""
Init.
# Arguments
resource: The Vortexa endpoint used for record lookups.
"""
self._api_resource = resource
def record(self, id: ID) -> Dict:
"""
Lookup for single record using ID.
# Arguments
id: ID of the record we're looking up
# Returns
A record matching the ID
# Examples
>>> Record("/cargo-movement/").record(id='cfb8c4ef76585c3a37792b643791a0f4ff6d5656d5508927d8017319e21f2fca') # doctest: +SKIP
"""
logger.info(
f"Looking up {self.__class__.__name__} single record data with id: {id}"
)
data = default_client().get_record(self._api_resource, id)
assert len(data) <= 1, InvalidAPIDataResponseException(
f"Server error: more than one record returned matching ID {id}"
)
try:
return data[0]
except IndexError:
return {}
def record_with_params(self, id: ID, params: Dict) -> Dict:
"""
Lookup for single record using ID and search params.
# Arguments
id: Cargo movement ID to lookup (long_id or short_id)
params: Supported search params:
'unit': enter 'b' for barrels, 't' for tonnes and 'cbm' for cubic meters
# Returns
A record matching the ID
# Examples
>>> Record("/cargo-movement").record(id='cfb8c4ef76585c3a37792b643791a0f4ff6d5656d5508927d8017319e21f2fca', {'unit': 'b'}) # doctest: +SKIP
"""
logger.info(
f"Looking up {self.__class__.__name__} single record data with id: {id}"
)
data = default_client().get_record_with_params(
self._api_resource, id, params
)
assert len(data) <= 1, InvalidAPIDataResponseException(
f"Server error: more than one record returned matching ID {id}"
)
try:
return data[0]
except IndexError:
return {}