From 5ee90103f58e44cfeae6eb27486ba5dc20bc5e29 Mon Sep 17 00:00:00 2001 From: speakeasybot Date: Fri, 1 Mar 2024 00:56:30 +0000 Subject: [PATCH] ci: regenerated with OpenAPI Doc 1.0.0, Speakeasy CLI 1.198.1 --- .speakeasy/gen.lock | 11 ++++-- RELEASES.md | 10 ++++- gen.yaml | 8 +++- pylintrc | 1 + setup.py | 10 +++-- src/test/_hooks/__init__.py | 4 ++ src/test/_hooks/sdkhooks.py | 55 ++++++++++++++++++++++++++++ src/test/_hooks/types.py | 70 +++++++++++++++++++++++++++++++++++ src/test/pets.py | 71 ++++++++++++++++++++++++++++++++++-- src/test/sdk.py | 11 ++++++ src/test/sdkconfiguration.py | 12 ++++-- src/test/utils/utils.py | 44 +++++++++++++++------- 12 files changed, 277 insertions(+), 30 deletions(-) create mode 100644 src/test/_hooks/__init__.py create mode 100644 src/test/_hooks/sdkhooks.py create mode 100644 src/test/_hooks/types.py diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 178c557..537ccc4 100755 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -4,15 +4,15 @@ management: docChecksum: 2516596125ef223fbbef6c434d22eaac docVersion: 1.0.0 speakeasyVersion: internal - generationVersion: 2.258.2 - releaseVersion: 0.13.1 - configChecksum: a0520f518d0ee53a5190269296d9a625 + generationVersion: 2.275.4 + releaseVersion: 0.14.0 + configChecksum: 3094cf1ed617220ed856b216803e40c9 repoURL: https://github.com/speakeasy-sdks/test-repo-test2.git repoSubDirectory: . installationURL: https://github.com/speakeasy-sdks/test-repo-test2.git features: python: - core: 4.4.6 + core: 4.5.0 globalServerURLs: 2.82.1 generatedFiles: - src/test/sdkconfiguration.py @@ -46,3 +46,6 @@ generatedFiles: - docs/sdks/pets/README.md - USAGE.md - .gitattributes + - src/test/_hooks/sdkhooks.py + - src/test/_hooks/types.py + - src/test/_hooks/__init__.py diff --git a/RELEASES.md b/RELEASES.md index ee01842..afb6555 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -310,4 +310,12 @@ Based on: - OpenAPI Doc 1.0.0 - Speakeasy CLI 1.180.1 (2.258.2) https://github.com/speakeasy-api/speakeasy ### Generated -- [python v0.13.1] . \ No newline at end of file +- [python v0.13.1] . + +## 2024-03-01 00:56:19 +### Changes +Based on: +- OpenAPI Doc 1.0.0 +- Speakeasy CLI 1.198.1 (2.275.4) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v0.14.0] . \ No newline at end of file diff --git a/gen.yaml b/gen.yaml index c301740..19762d6 100644 --- a/gen.yaml +++ b/gen.yaml @@ -7,8 +7,14 @@ generation: nameResolutionDec2023: false parameterOrderingFeb2024: false requestResponseComponentNamesFeb2024: false + auth: + oAuth2ClientCredentialsEnabled: false python: - version: 0.13.1 + version: 0.14.0 + additionalDependencies: + dependencies: {} + extraDependencies: + dev: {} author: my-test clientServerStatusCodesAsErrors: true description: Python Client SDK Generated by Speakeasy diff --git a/pylintrc b/pylintrc index cebe76d..0690eda 100644 --- a/pylintrc +++ b/pylintrc @@ -180,6 +180,7 @@ good-names=i, ex, Run, _, + e, id # Good variable names regexes, separated by a comma. If names match any regex, diff --git a/setup.py b/setup.py index c91dddb..e58b221 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setuptools.setup( name="test", - version="0.13.1", + version="0.14.0", author="my-test", description="Python Client SDK Generated by Speakeasy", long_description=long_description, @@ -19,9 +19,9 @@ install_requires=[ "certifi>=2023.7.22", "charset-normalizer>=3.2.0", - "dataclasses-json-speakeasy>=0.5.11", + "dataclasses-json>=0.6.4", "idna>=3.4", - "jsonpath-python>=1.0.6 ", + "jsonpath-python>=1.0.6", "marshmallow>=3.19.0", "mypy-extensions>=1.0.0", "packaging>=23.1", @@ -33,7 +33,9 @@ "urllib3>=1.26.18", ], extras_require={ - "dev":["pylint==2.16.2"] + "dev": [ + "pylint==2.16.2", + ], }, package_dir={'': 'src'}, python_requires='>=3.8', diff --git a/src/test/_hooks/__init__.py b/src/test/_hooks/__init__.py new file mode 100644 index 0000000..b2ab14b --- /dev/null +++ b/src/test/_hooks/__init__.py @@ -0,0 +1,4 @@ +"""Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.""" + +from .sdkhooks import * +from .types import * diff --git a/src/test/_hooks/sdkhooks.py b/src/test/_hooks/sdkhooks.py new file mode 100644 index 0000000..a8f9a58 --- /dev/null +++ b/src/test/_hooks/sdkhooks.py @@ -0,0 +1,55 @@ +"""Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.""" + +import requests +from .types import SDKInitHook, BeforeRequestContext, BeforeRequestHook, AfterSuccessContext, AfterSuccessHook, AfterErrorContext, AfterErrorHook, Hooks +from typing import List, Optional, Tuple, Union + + +class SDKHooks(Hooks): + sdk_init_hooks: List[SDKInitHook] = [] + before_request_hooks: List[BeforeRequestHook] = [] + after_success_hooks: List[AfterSuccessHook] = [] + after_error_hooks: List[AfterErrorHook] = [] + + def __init__(self): + pass + + def register_sdk_init_hook(self, hook: SDKInitHook) -> None: + self.sdk_init_hooks.append(hook) + + def register_before_request_hook(self, hook: BeforeRequestHook) -> None: + self.before_request_hooks.append(hook) + + def register_after_success_hook(self, hook: AfterSuccessHook) -> None: + self.after_success_hooks.append(hook) + + def register_after_error_hook(self, hook: AfterErrorHook) -> None: + self.after_error_hooks.append(hook) + + def sdk_init(self, base_url: str, client: requests.Session) -> Tuple[str, requests.Session]: + for hook in self.sdk_init_hooks: + base_url, client = hook.sdk_init(base_url, client) + return base_url, client + + def before_request(self, hook_ctx: BeforeRequestContext, request: requests.PreparedRequest) -> Union[requests.PreparedRequest, Exception]: + for hook in self.before_request_hooks: + request = hook.before_request(hook_ctx, request) + if isinstance(request, Exception): + raise request + + return request + + def after_success(self, hook_ctx: AfterSuccessContext, response: requests.Response) -> requests.Response: + for hook in self.after_success_hooks: + response = hook.after_success(hook_ctx, response) + if isinstance(response, Exception): + raise response + return response + + def after_error(self, hook_ctx: AfterErrorContext, response: Optional[requests.Response], error: Optional[Exception]) -> Tuple[Optional[requests.Response], Optional[Exception]]: + for hook in self.after_error_hooks: + result = hook.after_error(hook_ctx, response, error) + if isinstance(result, Exception): + raise result + response, error = result + return response, error diff --git a/src/test/_hooks/types.py b/src/test/_hooks/types.py new file mode 100644 index 0000000..d2fa862 --- /dev/null +++ b/src/test/_hooks/types.py @@ -0,0 +1,70 @@ +"""Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.""" + +import requests as requests_http +from abc import ABC, abstractmethod +from typing import Any, Callable, List, Optional, Tuple, Union + + +class HookContext: + operation_id: str + oauth2_scopes: Optional[List[str]] = None + security_source: Optional[Union[Any, Callable[[], Any]]] = None + + def __init__(self, operation_id: str, oauth2_scopes: Optional[List[str]], security_source: Optional[Union[Any, Callable[[], Any]]]): + self.operation_id = operation_id + self.oauth2_scopes = oauth2_scopes + self.security_source = security_source + + +class BeforeRequestContext(HookContext): + pass + + +class AfterSuccessContext(HookContext): + pass + + +class AfterErrorContext(HookContext): + pass + + +class SDKInitHook(ABC): + @abstractmethod + def sdk_init(self, base_url: str, client: requests_http.Session) -> Tuple[str, requests_http.Session]: + pass + + +class BeforeRequestHook(ABC): + @abstractmethod + def before_request(self, hook_ctx: BeforeRequestContext, request: requests_http.PreparedRequest) -> Union[requests_http.PreparedRequest, Exception]: + pass + + +class AfterSuccessHook(ABC): + @abstractmethod + def after_success(self, hook_ctx: AfterSuccessContext, response: requests_http.Response) -> Union[requests_http.PreparedRequest, Exception]: + pass + + +class AfterErrorHook(ABC): + @abstractmethod + def after_error(self, hook_ctx: AfterErrorContext, response: Optional[requests_http.Response], error: Optional[Exception]) -> Union[Tuple[Optional[requests_http.PreparedRequest], Optional[Exception]], Exception]: + pass + + +class Hooks(ABC): + @abstractmethod + def register_sdk_init_hook(self, hook: SDKInitHook): + pass + + @abstractmethod + def register_before_request_hook(self, hook: BeforeRequestHook): + pass + + @abstractmethod + def register_after_success_hook(self, hook: AfterSuccessHook): + pass + + @abstractmethod + def register_after_error_hook(self, hook: AfterErrorHook): + pass diff --git a/src/test/pets.py b/src/test/pets.py index 393973f..71bf89b 100644 --- a/src/test/pets.py +++ b/src/test/pets.py @@ -1,7 +1,9 @@ """Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.""" +import requests as requests_http from .sdkconfiguration import SDKConfiguration from test import utils +from test._hooks import HookContext from test.models import errors, operations, shared from typing import List, Optional @@ -15,6 +17,7 @@ def __init__(self, sdk_config: SDKConfiguration) -> None: def create_pets(self) -> operations.CreatePetsResponse: r"""Create a pet""" + hook_ctx = HookContext(operation_id='createPets', oauth2_scopes=[], security_source=None) base_url = utils.template_url(*self.sdk_configuration.get_server_details()) url = base_url + '/pets' @@ -24,7 +27,27 @@ def create_pets(self) -> operations.CreatePetsResponse: client = self.sdk_configuration.client - http_res = client.request('POST', url, headers=headers) + + try: + req = self.sdk_configuration.get_hooks().before_request( + hook_ctx, + requests_http.Request('POST', url, headers=headers).prepare(), + ) + http_res = client.send(req) + except Exception as e: + _, e = self.sdk_configuration.get_hooks().after_error(hook_ctx, None, e) + raise e + + if utils.match_status_codes(['4XX','5XX'], http_res.status_code): + http_res, e = self.sdk_configuration.get_hooks().after_error(hook_ctx, http_res, None) + if e: + raise e + else: + result = self.sdk_configuration.get_hooks().after_success(hook_ctx, http_res) + if isinstance(result, Exception): + raise result + http_res = result + content_type = http_res.headers.get('Content-Type') res = operations.CreatePetsResponse(status_code=http_res.status_code, content_type=content_type, raw_response=http_res) @@ -46,6 +69,7 @@ def create_pets(self) -> operations.CreatePetsResponse: def list_pets(self, request: operations.ListPetsRequest) -> operations.ListPetsResponse: r"""List all pets""" + hook_ctx = HookContext(operation_id='listPets', oauth2_scopes=[], security_source=None) base_url = utils.template_url(*self.sdk_configuration.get_server_details()) url = base_url + '/pets' @@ -56,7 +80,27 @@ def list_pets(self, request: operations.ListPetsRequest) -> operations.ListPetsR client = self.sdk_configuration.client - http_res = client.request('GET', url, params=query_params, headers=headers) + + try: + req = self.sdk_configuration.get_hooks().before_request( + hook_ctx, + requests_http.Request('GET', url, params=query_params, headers=headers).prepare(), + ) + http_res = client.send(req) + except Exception as e: + _, e = self.sdk_configuration.get_hooks().after_error(hook_ctx, None, e) + raise e + + if utils.match_status_codes(['4XX','5XX'], http_res.status_code): + http_res, e = self.sdk_configuration.get_hooks().after_error(hook_ctx, http_res, None) + if e: + raise e + else: + result = self.sdk_configuration.get_hooks().after_success(hook_ctx, http_res) + if isinstance(result, Exception): + raise result + http_res = result + content_type = http_res.headers.get('Content-Type') res = operations.ListPetsResponse(status_code=http_res.status_code, content_type=content_type, raw_response=http_res, headers=None) @@ -84,6 +128,7 @@ def list_pets(self, request: operations.ListPetsRequest) -> operations.ListPetsR def show_pet_by_id(self, request: operations.ShowPetByIDRequest) -> operations.ShowPetByIDResponse: r"""Info for a specific pet""" + hook_ctx = HookContext(operation_id='showPetById', oauth2_scopes=[], security_source=None) base_url = utils.template_url(*self.sdk_configuration.get_server_details()) url = utils.generate_url(operations.ShowPetByIDRequest, base_url, '/pets/{petId}', request) @@ -93,7 +138,27 @@ def show_pet_by_id(self, request: operations.ShowPetByIDRequest) -> operations.S client = self.sdk_configuration.client - http_res = client.request('GET', url, headers=headers) + + try: + req = self.sdk_configuration.get_hooks().before_request( + hook_ctx, + requests_http.Request('GET', url, headers=headers).prepare(), + ) + http_res = client.send(req) + except Exception as e: + _, e = self.sdk_configuration.get_hooks().after_error(hook_ctx, None, e) + raise e + + if utils.match_status_codes(['4XX','5XX'], http_res.status_code): + http_res, e = self.sdk_configuration.get_hooks().after_error(hook_ctx, http_res, None) + if e: + raise e + else: + result = self.sdk_configuration.get_hooks().after_success(hook_ctx, http_res) + if isinstance(result, Exception): + raise result + http_res = result + content_type = http_res.headers.get('Content-Type') res = operations.ShowPetByIDResponse(status_code=http_res.status_code, content_type=content_type, raw_response=http_res) diff --git a/src/test/sdk.py b/src/test/sdk.py index 39cac9f..76d383a 100644 --- a/src/test/sdk.py +++ b/src/test/sdk.py @@ -4,6 +4,7 @@ from .pets import Pets from .sdkconfiguration import SDKConfiguration from test import utils +from test._hooks import SDKHooks from typing import Dict class Test: @@ -39,6 +40,16 @@ def __init__(self, server_url = utils.template_url(server_url, url_params) self.sdk_configuration = SDKConfiguration(client, None, server_url, server_idx, retry_config=retry_config) + + hooks = SDKHooks() + + current_server_url, *_ = self.sdk_configuration.get_server_details() + server_url, self.sdk_configuration.client = hooks.sdk_init(current_server_url, self.sdk_configuration.client) + if current_server_url != server_url: + self.sdk_configuration.server_url = server_url + + # pylint: disable=protected-access + self.sdk_configuration._hooks=hooks self._init_sdks() diff --git a/src/test/sdkconfiguration.py b/src/test/sdkconfiguration.py index 88207d2..2bcc9a2 100644 --- a/src/test/sdkconfiguration.py +++ b/src/test/sdkconfiguration.py @@ -2,6 +2,7 @@ import requests as requests_http +from ._hooks import SDKHooks from .utils import utils from .utils.retries import RetryConfig from dataclasses import dataclass @@ -20,10 +21,11 @@ class SDKConfiguration: server_idx: int = 0 language: str = 'python' openapi_doc_version: str = '1.0.0' - sdk_version: str = '0.13.1' - gen_version: str = '2.258.2' - user_agent: str = 'speakeasy-sdk/python 0.13.1 2.258.2 1.0.0 test' + sdk_version: str = '0.14.0' + gen_version: str = '2.275.4' + user_agent: str = 'speakeasy-sdk/python 0.14.0 2.275.4 1.0.0 test' retry_config: RetryConfig = None + _hooks: SDKHooks = None def get_server_details(self) -> Tuple[str, Dict[str, str]]: if self.server_url: @@ -32,3 +34,7 @@ def get_server_details(self) -> Tuple[str, Dict[str, str]]: self.server_idx = 0 return SERVERS[self.server_idx], {} + + + def get_hooks(self) -> SDKHooks: + return self._hooks diff --git a/src/test/utils/utils.py b/src/test/utils/utils.py index 5243402..691091c 100644 --- a/src/test/utils/utils.py +++ b/src/test/utils/utils.py @@ -21,15 +21,16 @@ class SecurityClient: client: requests.Session query_params: Dict[str, str] = {} + headers: Dict[str, str] = {} def __init__(self, client: requests.Session): self.client = client - def request(self, method, url, **kwargs): - params = kwargs.get('params', {}) - kwargs["params"] = {**self.query_params, **params} + def send(self, request: requests.PreparedRequest, **kwargs): + request.prepare_url(url=request.url, params=self.query_params) + request.headers.update(self.headers) - return self.client.request(method, url, **kwargs) + return self.client.send(request, **kwargs) def configure_security_client(client: requests.Session, security: dataclass): @@ -102,20 +103,19 @@ def _parse_security_scheme_value(client: SecurityClient, scheme_metadata: Dict, if scheme_type == "apiKey": if sub_type == 'header': - client.client.headers[header_name] = value + client.headers[header_name] = value elif sub_type == 'query': client.query_params[header_name] = value - elif sub_type == 'cookie': - client.client.cookies[header_name] = value else: raise Exception('not supported') elif scheme_type == "openIdConnect": - client.client.headers[header_name] = _apply_bearer(value) + client.headers[header_name] = _apply_bearer(value) elif scheme_type == 'oauth2': - client.client.headers[header_name] = _apply_bearer(value) + if sub_type != 'client_credentials': + client.headers[header_name] = _apply_bearer(value) elif scheme_type == 'http': if sub_type == 'bearer': - client.client.headers[header_name] = _apply_bearer(value) + client.headers[header_name] = _apply_bearer(value) else: raise Exception('not supported') else: @@ -145,7 +145,7 @@ def _parse_basic_auth_scheme(client: SecurityClient, scheme: dataclass): password = value data = f'{username}:{password}'.encode() - client.client.headers['Authorization'] = f'Basic {base64.b64encode(data).decode()}' + client.headers['Authorization'] = f'Basic {base64.b64encode(data).decode()}' def generate_url(clazz: type, server_url: str, path: str, path_params: dataclass, @@ -264,7 +264,8 @@ def get_query_params(clazz: type, query_params: dataclass, gbls: Dict[str, Dict[ f_name = metadata.get("field_name") serialization = metadata.get('serialization', '') if serialization != '': - serialized_parms = _get_serialized_params(metadata, field.type, f_name, value) + serialized_parms = _get_serialized_params( + metadata, field.type, f_name, value) for key, value in serialized_parms.items(): if key in params: params[key].extend(value) @@ -312,7 +313,8 @@ def _get_serialized_params(metadata: Dict, field_type: type, field_name: str, ob serialization = metadata.get('serialization', '') if serialization == 'json': - params[metadata.get("field_name", field_name)] = marshal_json(obj, field_type) + params[metadata.get("field_name", field_name) + ] = marshal_json(obj, field_type) return params @@ -702,7 +704,8 @@ def unmarshal_json(data, typ, decoder=None): def marshal_json(val, typ, encoder=None): if not is_optional_type(typ) and val is None: - raise ValueError(f"Could not marshal None into non-optional type: {typ}") + raise ValueError( + f"Could not marshal None into non-optional type: {typ}") marshal = make_dataclass('Marshal', [('res', typ)], bases=(DataClassJsonMixin,)) @@ -732,6 +735,16 @@ def match_content_type(content_type: str, pattern: str) -> boolean: return False +def match_status_codes(status_codes: List[str], status_code: int) -> bool: + for code in status_codes: + if code == str(status_code): + return True + + if code.endswith("XX") and code.startswith(str(status_code)[:1]): + return True + return False + + def datetimeisoformat(optional: bool): def isoformatoptional(val): if optional and val is None: @@ -835,6 +848,7 @@ def list_decode(val: List): return list_decode + def union_encoder(all_encoders: Dict[str, Callable]): def selective_encoder(val: any): if type(val) in all_encoders: @@ -842,6 +856,7 @@ def selective_encoder(val: any): return val return selective_encoder + def union_decoder(all_decoders: List[Callable]): def selective_decoder(val: any): decoded = val @@ -854,6 +869,7 @@ def selective_decoder(val: any): return decoded return selective_decoder + def get_field_name(name): def override(_, _field_name=name): return _field_name