Skip to content

Commit 8ab7642

Browse files
authored
Fix/added tests improvements and documentation (#2)
* fix: Modified coverage * feat: Generated doc strings * feat: Updated README.md * fix: Fixed order of arguments in methods
1 parent 5f7d30d commit 8ab7642

33 files changed

Lines changed: 8552 additions & 149 deletions

File tree

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,34 @@ auth_backend = AuthSession(
3737
storage_client = OSDUAPI.client('storage', auth_backend=auth_backend)
3838
response = storage_client.get_record_versions(id="123")
3939

40-
```
40+
```
41+
# Available services
42+
43+
```python
44+
from osdu_client.client import OSDUAPI
45+
OSDUAPI.print_available_services()
46+
```
47+
48+
```bash
49+
| Name | Versions |
50+
===================================
51+
| dataset | latest |
52+
| entitlements | latest |
53+
| file | latest |
54+
| indexer | latest |
55+
| legal | latest |
56+
| notification | latest |
57+
| partition | latest |
58+
| policy | latest |
59+
| pws | latest |
60+
| rafs | v1, v2 |
61+
| register | latest |
62+
| schema | latest |
63+
| sdms | latest |
64+
| search | latest |
65+
| secret | latest |
66+
| storage | latest |
67+
| wellbore | v2, v3 |
68+
| welldelivery | latest |
69+
```
70+

gen/client_generator.py

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ def get_type_for_param(param: dict, swagger: dict | None = None) -> str:
6868
all_of = get_path(param, "allOf.0.$ref", None)
6969
any_of = get_path(param, "anyOf", None)
7070

71-
7271
if any_of:
7372
types = []
7473
_list = any_of
@@ -86,6 +85,8 @@ def get_type_for_param(param: dict, swagger: dict | None = None) -> str:
8685
types.append(
8786
COMPLEX_TYPES_MAP[(_type, items_type)]
8887
)
88+
if len(types) == 1:
89+
return types[0]
8990
return "Union[%s]" % ", ".join(types)
9091

9192
while ref_path or all_of:
@@ -171,8 +172,8 @@ def create_headers_block(required_header_params_without_special, optional_header
171172
"headers = self.auth.get_headers()",
172173
"if data_partition_id:",
173174
f"{INDENT}headers['data-partition-id'] = data_partition_id",
174-
#"if tenant:",
175-
#f"{INDENT}headers['tenant'] = tenant"
175+
# "if tenant:",
176+
# f"{INDENT}headers['tenant'] = tenant"
176177
]
177178
if required_header_params_without_special:
178179
lines.append(
@@ -326,12 +327,8 @@ def get_name_from_name_map(method: str, path: str, method_names_file: str):
326327

327328

328329
def create_method_name(method: str, path: str, name_parts: list[str], swagger: dict, method_names_file: str) -> str:
329-
# try:
330330
summary = swagger["paths"][path][method].get("summary")
331331
description = swagger["paths"][path][method].get("description", "")
332-
# except TypeError as e:
333-
# print(name_parts, path)
334-
# raise e
335332
name = get_name_from_name_map(method, path, method_names_file)
336333

337334
if name:
@@ -447,7 +444,7 @@ def create_validation_block(path: str, method: str, swagger: dict, name: str) ->
447444
model_class = schema_path.rsplit("/", 1)[-1]
448445
lines = [
449446
"if self.validation:",
450-
"%svalidate_data(request_data, %s, %sAPIError)" % (INDENT, model_class, name),
447+
"%svalidate_data(request_data, %s)" % (INDENT, model_class),
451448
]
452449
return "\n".join(lines)
453450
return ""
@@ -493,7 +490,7 @@ def create_method(swagger: dict, name: str, method: str, path: str, path_templat
493490

494491
body_required, body_not_required = get_body_params(swagger, params, request_body)
495492

496-
sig = create_method_sig(swagger, name, params, body_required, body_not_required) + "\n"
493+
sig = create_method_sig(swagger, name, params, body_required, body_not_required, method, path) + "\n"
497494

498495
body = create_method_body(path, method, params, body_required,
499496
body_not_required, path_template, class_name, swagger)
@@ -513,33 +510,77 @@ def parse_request_body(swagger: dict, props: list[dict]) -> list[str]:
513510
return result
514511

515512

516-
def create_method_sig(swagger: dict, name: str, params: list[str], body_required: list[str], body_not_required: list[str]) -> str:
513+
def generate_doc_string(name, path_params, body_required, body_not_required, swagger, method, path, indent_offset: int = 1):
514+
description = swagger['paths'][path][method].get("description", "")
515+
description = re.sub('<[^<]+>', "", description)
516+
lines_1 = [
517+
(INDENT*(indent_offset))+'"""',
518+
(INDENT*(indent_offset))+description,
519+
(INDENT*(indent_offset))+"Args:",
520+
(INDENT*(indent_offset+1))+"data_partition_id (str): identifier of the data partition to query. If None sets by auth session.",
521+
]
522+
for path_param in path_params:
523+
name = convert_to_snake_case(path_param["name"])
524+
_type = get_type_for_param(path_param, swagger)
525+
lines_1.append(
526+
(INDENT*(indent_offset+1)) + f"{name} ({_type}): {path_param.get('description', '')}"
527+
)
528+
529+
for param in body_required:
530+
name = convert_to_snake_case(param["name"])
531+
_type = get_type_for_param(param, swagger)
532+
lines_1.append(
533+
(INDENT*(indent_offset+1)) + f"{name} ({_type}): {param.get('description', '')}"
534+
)
535+
536+
for param in body_not_required:
537+
name = convert_to_snake_case(param["name"])
538+
_type = get_type_for_param(param, swagger)
539+
lines_1.append(
540+
(INDENT*(indent_offset+1)) + f"{name} ({_type}): {param.get('description', '')}"
541+
)
542+
543+
lines_2 = [
544+
(INDENT*(indent_offset))+"Returns:",
545+
(INDENT*(indent_offset+1))+"response data (dict)",
546+
(INDENT*(indent_offset))+"Raises:",
547+
(INDENT*(indent_offset+1))+"OSDUValidation: if request values are wrong.",
548+
(INDENT*(indent_offset+1))+"OSDUAPIError: if response is 4XX or 5XX",
549+
(INDENT*(indent_offset))+'"""'
550+
]
551+
result = "\n".join(lines_1 + lines_2)
552+
return result
553+
554+
555+
def create_method_sig(swagger: dict, name: str, params: list[str], body_required: list[str], body_not_required: list[str], method: str, path: str) -> str:
517556
path_params = [
518557
p for p in params if p['name'] not in SPECIAL_HEADERS and p["in"] != "body"
519558
]
520559
elements = [name, ]
521560
sig = ""
522-
_input_parameters_strings = []
561+
_input_parameters_strings = [param_to_function_argument(p)
562+
for p in path_params]
523563

524564
if body_required:
525565
_input_parameters_strings += parse_request_body(swagger, body_required)
566+
526567
if body_not_required:
527568
_input_parameters_strings += parse_request_body(swagger, body_not_required)
528-
529-
_input_parameters_strings += [param_to_function_argument(p) for p in sorted(path_params, key=lambda x: 0 if x.get("required") else 1)]
530-
569+
531570
if _input_parameters_strings:
532571
sig += ", ".join(_input_parameters_strings)
533572

534573
if sig:
535574
elements.append(sig)
536575

576+
doc = generate_doc_string(name, path_params, body_required, body_not_required,
577+
swagger, method, path, indent_offset=1)
537578
try:
538579
if len(elements) > 1:
539580
sig = "def %s(self, *, %s, data_partition_id: str | None = None) -> dict:" % tuple(elements)
540581
else:
541582
sig = "def %s(self, data_partition_id: str | None = None) -> dict:" % tuple(elements)
542-
return sig
583+
return sig + "\n" + doc
543584
except Exception as e:
544585
raise Exception(elements, len(elements)) from e
545586

gen/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
import os
3-
import sys
43
import re
4+
import sys
55
from subprocess import PIPE, Popen
66
from typing import Any
77

gen/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ ruff
33
datamodel-code-generator
44
PyYAML
55
pydantic
6+
lxml

gen/run_generation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
WORKDIR = os.getcwd()
1010

1111
SERVICES = {
12-
"Entitlements": "https://community.opengroup.org/osdu/platform/security-and-compliance/entitlements/-/raw/master/docs/api/entitlements_openapi.yaml?ref_type=heads",
1312
"SDMS": "https://community.opengroup.org/osdu/platform/domain-data-mgmt-services/seismic/seismic-dms-suite/seismic-store-service/-/raw/master/app/sdms/docs/api/openapi.osdu.yaml?ref_type=heads",
13+
"Entitlements": "https://community.opengroup.org/osdu/platform/security-and-compliance/entitlements/-/raw/master/docs/api/entitlements_openapi.yaml?ref_type=heads",
1414
"Storage": "https://community.opengroup.org/osdu/platform/system/storage/-/raw/master/docs/api/storage_openapi.yaml?ref_type=heads",
1515
"Search": "https://community.opengroup.org/osdu/platform/system/search-service/-/raw/master/docs/api/search_openapi.yaml?ref_type=heads",
1616
"Indexer": "https://community.opengroup.org/osdu/platform/system/indexer-service/-/raw/master/docs/api/indexer_openapi.yaml?ref_type=heads",
@@ -65,7 +65,7 @@ def remove_path_if_empty(path: str):
6565
swagger_path,
6666
models_path+".py",
6767
)
68-
if not os.path.exists(os.path.join(module_path, "client.py")):
68+
if not os.path.exists(os.path.join(module_path, "client.py")) or True:
6969
generate_clients(
7070
swagger_path,
7171
name,

osdu_client/client.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,48 @@ def get_service_client(name: str, version: str | None = None) -> type[OSDUAPICli
3939
class OSDUAPI:
4040
@staticmethod
4141
def client(service_name, auth_backend: AuthBackendInterface, version: str | None = None, validation: bool = True) -> OSDUAPIClient:
42+
"""Creates client instance for given service.
43+
Args:
44+
service_name (str): The OSDU API service name, to check available services call list_available_services method.
45+
auth_backend (AuthBackendInterface): class object that implements AuthBackendInterface and stores all auth headers.
46+
version (str): Version of the service API client. If None method will produce the latest client.
47+
validation (bool): Disable to turn-off request body validation done before client makes a request. By default True
48+
Returns:
49+
Instance of OSDUAPIClient for given service_name
50+
Raises:
51+
OSDUClientError: if bad arguments provided
52+
53+
"""
4254
client_class = get_service_client(service_name, version)
4355
return client_class(
4456
auth_backend=auth_backend,
4557
validation=validation,
4658
)
59+
60+
@classmethod
61+
def print_available_services(cls):
62+
"""
63+
Prints available services for client
64+
"""
65+
print("| Name | Versions |")
66+
print("===================================")
67+
for k, v in cls.list_available_services():
68+
print("|", end="")
69+
space = 16 - len(k)
70+
print((" "*(space//2))+k+(" "*((space//2) + space % 2)), end="")
71+
print("|", end="")
72+
versions_str = str(v)[1:-1].replace("'", "")
73+
versions_str = versions_str if len(versions_str) else "latest"
74+
space = 16 - len(versions_str)
75+
print(" "*(space//2)+versions_str+(" "*((space//2) + space % 2)), end="")
76+
print("|")
77+
78+
@staticmethod
79+
def list_available_services() -> list[tuple[str, list[str]]]:
80+
"""
81+
Returns list of available services for client
82+
Returns:
83+
list of available services for API versions (list[tuple[str, list[str]]])
84+
"""
85+
module = import_module("osdu_client.services")
86+
return [(k, v) for k, v in module.SERVICES.items()]

osdu_client/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ class OSDUClientError(Exception):
55

66
class OSDUAPIError(OSDUClientError):
77
pass
8+
9+
10+
class OSDUValidation(OSDUClientError):
11+
pass

osdu_client/services/__init__.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from osdu_client.services import rafs, wellbore
2+
3+
SERVICES = {
4+
"dataset": [],
5+
"entitlements": [],
6+
"file": [],
7+
"indexer": [],
8+
"legal": [],
9+
"notification": [],
10+
"partition": [],
11+
"policy": [],
12+
"pws": [],
13+
"rafs": list(rafs.VERSIONS.keys()),
14+
"register": [],
15+
"schema": [],
16+
"sdms": [],
17+
"search": [],
18+
"secret": [],
19+
"storage": [],
20+
"wellbore": list(wellbore.VERSIONS.keys()),
21+
"welldelivery": [],
22+
}

0 commit comments

Comments
 (0)