From d6b3c89aace7bd958699f55dfab9a0cec41d3d0e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:24:46 -0500 Subject: [PATCH] =?UTF-8?q?chore:=20=F0=9F=90=9D=20Update=20SDK=20-=20Gene?= =?UTF-8?q?rate=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # SDK update Based on: - OpenAPI Doc 0.0.1 - Speakeasy CLI 1.204.1 (2.279.1) https://github.com/speakeasy-api/speakeasy ## PYTHON CHANGELOG ## responseFormat: 0.1.0 - 2024-03-02 ### :bee: New Features - add support for response formats and flat responses *(commit by [@TristanSpeakeasy](https://github.com/TristanSpeakeasy))* ## core: 4.5.1 - 2024-03-06 ### :bug: Bug Fixes - fixes to security header handling to be compatible with hooks *(commit by [@tristanspeakeasy](https://github.com/tristanspeakeasy))* - fix py.typed file *(commit by [@ryan-timothy-albert](https://github.com/ryan-timothy-albert))* ## core: 4.4.7 - 2024-02-23 ### :bug: Bug Fixes - example generation for complex objects *(commit by [@ThomasRooney](https://github.com/ThomasRooney))* --------- Co-authored-by: speakeasybot Co-authored-by: John <43506685+Coniferish@users.noreply.github.com> --- .speakeasy/gen.lock | 13 +-- RELEASES.md | 12 ++- USAGE.md | 1 + gen.yaml | 3 +- py.typed | 1 + setup.py | 2 +- src/unstructured_client/_hooks/sdkhooks.py | 9 +- src/unstructured_client/general.py | 32 +++--- src/unstructured_client/sdk.py | 2 +- src/unstructured_client/sdkconfiguration.py | 6 +- src/unstructured_client/utils/retries.py | 2 +- src/unstructured_client/utils/utils.py | 107 +++++++++----------- 12 files changed, 96 insertions(+), 94 deletions(-) create mode 100644 py.typed diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 9076896c..4b00e89b 100755 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -3,21 +3,22 @@ id: 8b5fa338-9106-4734-abf0-e30d67044a90 management: docChecksum: 0474212adfef86a6c183841a3cb9d75b docVersion: 0.0.1 - speakeasyVersion: internal - generationVersion: 2.277.0 - releaseVersion: 0.21.1 - configChecksum: 37b07ca4ef319a1d49602f97748e7aba + speakeasyVersion: 1.204.1 + generationVersion: 2.279.1 + releaseVersion: 0.22.0 + configChecksum: e458fc5426aa3514cb9bd40351fff33a repoURL: https://github.com/Unstructured-IO/unstructured-python-client.git repoSubDirectory: . installationURL: https://github.com/Unstructured-IO/unstructured-python-client.git published: true features: python: - core: 4.5.0 + core: 4.5.1 examples: 2.81.3 globalSecurity: 2.83.4 globalServerURLs: 2.82.1 nameOverrides: 2.81.1 + responseFormat: 0.1.0 retries: 2.82.1 serverIDs: 2.81.1 unions: 2.82.6 @@ -25,6 +26,7 @@ generatedFiles: - src/unstructured_client/sdkconfiguration.py - src/unstructured_client/general.py - src/unstructured_client/sdk.py + - py.typed - pylintrc - setup.py - src/unstructured_client/__init__.py @@ -51,7 +53,6 @@ generatedFiles: - docs/models/shared/security.md - USAGE.md - .gitattributes - - src/unstructured_client/_hooks/registration.py - src/unstructured_client/_hooks/sdkhooks.py - src/unstructured_client/_hooks/types.py - src/unstructured_client/_hooks/__init__.py diff --git a/RELEASES.md b/RELEASES.md index af8d0153..f5a58275 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -464,4 +464,14 @@ Based on: ### Generated - [python v0.21.1] . ### Releases -- [PyPI v0.21.1] https://pypi.org/project/unstructured-client/0.21.1 - . \ No newline at end of file +- [PyPI v0.21.1] https://pypi.org/project/unstructured-client/0.21.1 - . + +## 2024-03-08 00:19:03 +### Changes +Based on: +- OpenAPI Doc 0.0.1 +- Speakeasy CLI 1.204.1 (2.279.1) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v0.22.0] . +### Releases +- [PyPI v0.22.0] https://pypi.org/project/unstructured-client/0.22.0 - . \ No newline at end of file diff --git a/USAGE.md b/USAGE.md index 919a0d13..680cb7c9 100644 --- a/USAGE.md +++ b/USAGE.md @@ -37,5 +37,6 @@ res = s.general.partition(req) if res.elements is not None: # handle response pass + ``` \ No newline at end of file diff --git a/gen.yaml b/gen.yaml index cbcdef5f..86054fdc 100644 --- a/gen.yaml +++ b/gen.yaml @@ -10,7 +10,7 @@ generation: auth: oAuth2ClientCredentialsEnabled: false python: - version: 0.21.1 + version: 0.22.0 additionalDependencies: dependencies: deepdiff: '>=6.0' @@ -34,3 +34,4 @@ python: maxMethodParams: 0 outputModelSuffix: output packageName: unstructured-client + responseFormat: envelope diff --git a/py.typed b/py.typed new file mode 100644 index 00000000..3e38f1a9 --- /dev/null +++ b/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561. The package enables type hints. diff --git a/setup.py b/setup.py index de7e065f..16a6b4fe 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setuptools.setup( name="unstructured-client", - version="0.21.1", + version="0.22.0", author="Unstructured", description="Python Client SDK for Unstructured API", license = "MIT", diff --git a/src/unstructured_client/_hooks/sdkhooks.py b/src/unstructured_client/_hooks/sdkhooks.py index a9ba878f..867a0741 100644 --- a/src/unstructured_client/_hooks/sdkhooks.py +++ b/src/unstructured_client/_hooks/sdkhooks.py @@ -7,12 +7,11 @@ 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): + self.sdk_init_hooks: List[SDKInitHook] = [] + self.before_request_hooks: List[BeforeRequestHook] = [] + self.after_success_hooks: List[AfterSuccessHook] = [] + self.after_error_hooks: List[AfterErrorHook] = [] init_hooks(self) def register_sdk_init_hook(self, hook: SDKInitHook) -> None: diff --git a/src/unstructured_client/general.py b/src/unstructured_client/general.py index c22c70f4..49a5269a 100644 --- a/src/unstructured_client/general.py +++ b/src/unstructured_client/general.py @@ -24,18 +24,18 @@ def partition(self, request: Optional[shared.PartitionParameters], retries: Opti base_url = utils.template_url(*self.sdk_configuration.get_server_details()) url = base_url + '/general/v0/general' - headers = {} + + if callable(self.sdk_configuration.security): + headers, query_params = utils.get_security(self.sdk_configuration.security()) + else: + headers, query_params = utils.get_security(self.sdk_configuration.security) + req_content_type, data, form = utils.serialize_request_body(request, Optional[shared.PartitionParameters], "request", False, True, 'multipart') if req_content_type is not None and req_content_type not in ('multipart/form-data', 'multipart/mixed'): headers['content-type'] = req_content_type headers['Accept'] = 'application/json' headers['user-agent'] = self.sdk_configuration.user_agent - - if callable(self.sdk_configuration.security): - client = utils.configure_security_client(self.sdk_configuration.client, self.sdk_configuration.security()) - else: - client = utils.configure_security_client(self.sdk_configuration.client, self.sdk_configuration.security) - + client = self.sdk_configuration.client global_retry_config = self.sdk_configuration.retry_config retry_config = retries @@ -45,11 +45,13 @@ def partition(self, request: Optional[shared.PartitionParameters], retries: Opti else: retry_config = utils.RetryConfig('backoff', utils.BackoffStrategy(500, 60000, 1.5, 900000), True) + req = None def do_request(): + nonlocal req try: req = self.sdk_configuration.get_hooks().before_request( hook_ctx, - requests_http.Request('POST', url, data=data, files=form, headers=headers).prepare(), + requests_http.Request('POST', url, params=query_params, data=data, files=form, headers=headers).prepare(), ) http_res = client.send(req) except Exception as e: @@ -72,26 +74,28 @@ def do_request(): '5xx' ])) - content_type = http_res.headers.get('Content-Type') - res = operations.PartitionResponse(status_code=http_res.status_code, content_type=content_type, raw_response=http_res) + res = operations.PartitionResponse(status_code=http_res.status_code, content_type=http_res.headers.get('Content-Type'), raw_response=http_res) if http_res.status_code == 200: - if utils.match_content_type(content_type, 'application/json'): + if utils.match_content_type(http_res.headers.get('Content-Type'), 'application/json'): out = utils.unmarshal_json(http_res.text, Optional[List[Any]]) res.elements = out else: + content_type = http_res.headers.get('Content-Type') raise errors.SDKError(f'unknown content-type received: {content_type}', http_res.status_code, http_res.text, http_res) elif http_res.status_code == 422: - if utils.match_content_type(content_type, 'application/json'): + if utils.match_content_type(http_res.headers.get('Content-Type'), 'application/json'): out = utils.unmarshal_json(http_res.text, errors.HTTPValidationError) - out.raw_response = http_res raise out else: + content_type = http_res.headers.get('Content-Type') raise errors.SDKError(f'unknown content-type received: {content_type}', http_res.status_code, http_res.text, http_res) elif http_res.status_code >= 400 and http_res.status_code < 500 or http_res.status_code >= 500 and http_res.status_code < 600: raise errors.SDKError('API error occurred', http_res.status_code, http_res.text, http_res) + else: + raise errors.SDKError('unknown status code received', http_res.status_code, http_res.text, http_res) return res - \ No newline at end of file + diff --git a/src/unstructured_client/sdk.py b/src/unstructured_client/sdk.py index c2da04cd..4dd9b7ba 100644 --- a/src/unstructured_client/sdk.py +++ b/src/unstructured_client/sdk.py @@ -9,7 +9,6 @@ from unstructured_client.models import shared from unstructured_client.utils._human_utils import clean_server_url # human code - class UnstructuredClient: r"""Unstructured Pipeline API: Partition documents with the Unstructured library""" general: General @@ -69,3 +68,4 @@ def security(): def _init_sdks(self): self.general = General(self.sdk_configuration) + diff --git a/src/unstructured_client/sdkconfiguration.py b/src/unstructured_client/sdkconfiguration.py index 28d277b7..eda71a00 100644 --- a/src/unstructured_client/sdkconfiguration.py +++ b/src/unstructured_client/sdkconfiguration.py @@ -29,9 +29,9 @@ class SDKConfiguration: server: str = '' language: str = 'python' openapi_doc_version: str = '0.0.1' - sdk_version: str = '0.21.1' - gen_version: str = '2.277.0' - user_agent: str = 'speakeasy-sdk/python 0.21.1 2.277.0 0.0.1 unstructured-client' + sdk_version: str = '0.22.0' + gen_version: str = '2.279.1' + user_agent: str = 'speakeasy-sdk/python 0.22.0 2.279.1 0.0.1 unstructured-client' retry_config: RetryConfig = None _hooks: SDKHooks = None diff --git a/src/unstructured_client/utils/retries.py b/src/unstructured_client/utils/retries.py index 6ffe8942..1543baa7 100644 --- a/src/unstructured_client/utils/retries.py +++ b/src/unstructured_client/utils/retries.py @@ -8,7 +8,6 @@ from unstructured_client.utils._human_utils import log_retries # human code - class BackoffStrategy: initial_interval: int max_interval: int @@ -121,3 +120,4 @@ def retry_with_backoff(func, initial_interval=500, max_interval=60000, exponent= log_retries(retry_count=retries+1, sleep=sleep, exception=exception) # human code time.sleep(sleep) retries += 1 + diff --git a/src/unstructured_client/utils/utils.py b/src/unstructured_client/utils/utils.py index 691091c8..44b7a2e0 100644 --- a/src/unstructured_client/utils/utils.py +++ b/src/unstructured_client/utils/utils.py @@ -4,7 +4,7 @@ import json import re import sys -from dataclasses import Field, dataclass, fields, is_dataclass, make_dataclass +from dataclasses import Field, fields, is_dataclass, make_dataclass from datetime import date, datetime from decimal import Decimal from email.message import Message @@ -14,30 +14,15 @@ from xmlrpc.client import boolean from typing_inspect import is_optional_type import dateutil.parser -import requests from dataclasses_json import DataClassJsonMixin -class SecurityClient: - client: requests.Session - query_params: Dict[str, str] = {} +def get_security(security: Any) -> Tuple[Dict[str, str], Dict[str, str]]: headers: Dict[str, str] = {} - - def __init__(self, client: requests.Session): - self.client = client - - 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.send(request, **kwargs) - - -def configure_security_client(client: requests.Session, security: dataclass): - client = SecurityClient(client) + query_params: Dict[str, str] = {} if security is None: - return client + return headers, query_params sec_fields: Tuple[Field, ...] = fields(security) for sec_field in sec_fields: @@ -49,35 +34,35 @@ def configure_security_client(client: requests.Session, security: dataclass): if metadata is None: continue if metadata.get('option'): - _parse_security_option(client, value) - return client + _parse_security_option(headers, query_params, value) + return headers, query_params if metadata.get('scheme'): # Special case for basic auth which could be a flattened struct if metadata.get("sub_type") == "basic" and not is_dataclass(value): - _parse_security_scheme(client, metadata, security) + _parse_security_scheme(headers, query_params, metadata, security) else: - _parse_security_scheme(client, metadata, value) + _parse_security_scheme(headers, query_params, metadata, value) - return client + return headers, query_params -def _parse_security_option(client: SecurityClient, option: dataclass): +def _parse_security_option(headers: Dict[str, str], query_params: Dict[str, str], option: Any): opt_fields: Tuple[Field, ...] = fields(option) for opt_field in opt_fields: metadata = opt_field.metadata.get('security') if metadata is None or metadata.get('scheme') is None: continue _parse_security_scheme( - client, metadata, getattr(option, opt_field.name)) + headers, query_params, metadata, getattr(option, opt_field.name)) -def _parse_security_scheme(client: SecurityClient, scheme_metadata: Dict, scheme: any): +def _parse_security_scheme(headers: Dict[str, str], query_params: Dict[str, str], scheme_metadata: Dict, scheme: Any): scheme_type = scheme_metadata.get('type') sub_type = scheme_metadata.get('sub_type') if is_dataclass(scheme): if scheme_type == 'http' and sub_type == 'basic': - _parse_basic_auth_scheme(client, scheme) + _parse_basic_auth_scheme(headers, scheme) return scheme_fields: Tuple[Field, ...] = fields(scheme) @@ -89,33 +74,33 @@ def _parse_security_scheme(client: SecurityClient, scheme_metadata: Dict, scheme value = getattr(scheme, scheme_field.name) _parse_security_scheme_value( - client, scheme_metadata, metadata, value) + headers, query_params, scheme_metadata, metadata, value) else: _parse_security_scheme_value( - client, scheme_metadata, scheme_metadata, scheme) + headers, query_params, scheme_metadata, scheme_metadata, scheme) -def _parse_security_scheme_value(client: SecurityClient, scheme_metadata: Dict, security_metadata: Dict, value: any): +def _parse_security_scheme_value(headers: Dict[str, str], query_params: Dict[str, str], scheme_metadata: Dict, security_metadata: Dict, value: Any): scheme_type = scheme_metadata.get('type') sub_type = scheme_metadata.get('sub_type') - header_name = security_metadata.get('field_name') + header_name = str(security_metadata.get('field_name')) if scheme_type == "apiKey": if sub_type == 'header': - client.headers[header_name] = value + headers[header_name] = value elif sub_type == 'query': - client.query_params[header_name] = value + query_params[header_name] = value else: raise Exception('not supported') elif scheme_type == "openIdConnect": - client.headers[header_name] = _apply_bearer(value) + headers[header_name] = _apply_bearer(value) elif scheme_type == 'oauth2': if sub_type != 'client_credentials': - client.headers[header_name] = _apply_bearer(value) + headers[header_name] = _apply_bearer(value) elif scheme_type == 'http': if sub_type == 'bearer': - client.headers[header_name] = _apply_bearer(value) + headers[header_name] = _apply_bearer(value) else: raise Exception('not supported') else: @@ -126,7 +111,7 @@ def _apply_bearer(token: str) -> str: return token.lower().startswith('bearer ') and token or f'Bearer {token}' -def _parse_basic_auth_scheme(client: SecurityClient, scheme: dataclass): +def _parse_basic_auth_scheme(headers: Dict[str, str], scheme: Any): username = "" password = "" @@ -145,11 +130,11 @@ def _parse_basic_auth_scheme(client: SecurityClient, scheme: dataclass): password = value data = f'{username}:{password}'.encode() - client.headers['Authorization'] = f'Basic {base64.b64encode(data).decode()}' + headers['Authorization'] = f'Basic {base64.b64encode(data).decode()}' -def generate_url(clazz: type, server_url: str, path: str, path_params: dataclass, - gbls: Dict[str, Dict[str, Dict[str, Any]]] = None) -> str: +def generate_url(clazz: type, server_url: str, path: str, path_params: Any, + gbls: Optional[Dict[str, Dict[str, Dict[str, Any]]]] = None) -> str: path_param_fields: Tuple[Field, ...] = fields(clazz) for field in path_param_fields: request_metadata = field.metadata.get('request') @@ -241,7 +226,7 @@ def template_url(url_with_params: str, params: Dict[str, str]) -> str: return url_with_params -def get_query_params(clazz: type, query_params: dataclass, gbls: Dict[str, Dict[str, Dict[str, Any]]] = None) -> Dict[ +def get_query_params(clazz: type, query_params: Any, gbls: Optional[Dict[str, Dict[str, Dict[str, Any]]]] = None) -> Dict[ str, List[str]]: params: Dict[str, List[str]] = {} @@ -287,7 +272,7 @@ def get_query_params(clazz: type, query_params: dataclass, gbls: Dict[str, Dict[ return params -def get_headers(headers_params: dataclass) -> Dict[str, str]: +def get_headers(headers_params: Any) -> Dict[str, str]: if headers_params is None: return {} @@ -308,7 +293,7 @@ def get_headers(headers_params: dataclass) -> Dict[str, str]: return headers -def _get_serialized_params(metadata: Dict, field_type: type, field_name: str, obj: any) -> Dict[str, str]: +def _get_serialized_params(metadata: Dict, field_type: type, field_name: str, obj: Any) -> Dict[str, str]: params: Dict[str, str] = {} serialization = metadata.get('serialization', '') @@ -319,7 +304,7 @@ def _get_serialized_params(metadata: Dict, field_type: type, field_name: str, ob return params -def _get_deep_object_query_params(metadata: Dict, field_name: str, obj: any) -> Dict[str, List[str]]: +def _get_deep_object_query_params(metadata: Dict, field_name: str, obj: Any) -> Dict[str, List[str]]: params: Dict[str, List[str]] = {} if obj is None: @@ -385,7 +370,7 @@ def _get_query_param_field_name(obj_field: Field) -> str: return obj_param_metadata.get("field_name", obj_field.name) -def _get_delimited_query_params(metadata: Dict, field_name: str, obj: any, delimiter: str) -> Dict[ +def _get_delimited_query_params(metadata: Dict, field_name: str, obj: Any, delimiter: str) -> Dict[ str, List[str]]: return _populate_form(field_name, metadata.get("explode", True), obj, _get_query_param_field_name, delimiter) @@ -399,8 +384,8 @@ def _get_delimited_query_params(metadata: Dict, field_name: str, obj: any, delim } -def serialize_request_body(request: dataclass, request_type: type, request_field_name: str, nullable: bool, optional: bool, serialization_method: str, encoder=None) -> Tuple[ - str, any, any]: +def serialize_request_body(request: Any, request_type: type, request_field_name: str, nullable: bool, optional: bool, serialization_method: str, encoder=None) -> Tuple[ + Optional[str], Optional[Any], Optional[Any]]: if request is None: if not nullable and optional: return None, None, None @@ -430,7 +415,7 @@ def serialize_request_body(request: dataclass, request_type: type, request_field request_val) -def serialize_content_type(field_name: str, request_type: any, media_type: str, request: dataclass, encoder=None) -> Tuple[str, any, List[List[any]]]: +def serialize_content_type(field_name: str, request_type: Any, media_type: str, request: Any, encoder=None) -> Tuple[Optional[str], Optional[Any], Optional[List[List[Any]]]]: if re.match(r'(application|text)\/.*?\+*json.*', media_type) is not None: return media_type, marshal_json(request, request_type, encoder), None if re.match(r'multipart\/.*', media_type) is not None: @@ -446,8 +431,8 @@ def serialize_content_type(field_name: str, request_type: any, media_type: str, f"invalid request body type {type(request)} for mediaType {media_type}") -def serialize_multipart_form(media_type: str, request: dataclass) -> Tuple[str, any, List[List[any]]]: - form: List[List[any]] = [] +def serialize_multipart_form(media_type: str, request: Any) -> Tuple[str, Any, List[List[Any]]]: + form: List[List[Any]] = [] request_fields = fields(request) for field in request_fields: @@ -502,7 +487,7 @@ def serialize_multipart_form(media_type: str, request: dataclass) -> Tuple[str, def serialize_dict(original: Dict, explode: bool, field_name, existing: Optional[Dict[str, List[str]]]) -> Dict[ str, List[str]]: if existing is None: - existing = [] + existing = {} if explode is True: for key, val in original.items(): @@ -520,7 +505,7 @@ def serialize_dict(original: Dict, explode: bool, field_name, existing: Optional return existing -def serialize_form_data(field_name: str, data: dataclass) -> Dict[str, any]: +def serialize_form_data(field_name: str, data: Any) -> Dict[str, Any]: form: Dict[str, List[str]] = {} if is_dataclass(data): @@ -562,7 +547,7 @@ def _get_form_field_name(obj_field: Field) -> str: return obj_param_metadata.get("field_name", obj_field.name) -def _populate_form(field_name: str, explode: boolean, obj: any, get_field_name_func: Callable, delimiter: str) -> \ +def _populate_form(field_name: str, explode: boolean, obj: Any, get_field_name_func: Callable, delimiter: str) -> \ Dict[str, List[str]]: params: Dict[str, List[str]] = {} @@ -597,7 +582,7 @@ def _populate_form(field_name: str, explode: boolean, obj: any, get_field_name_f continue if explode: - params[key] = _val_to_string(value) + params[key] = [_val_to_string(value)] else: items.append(f'{key}{delimiter}{_val_to_string(value)}') @@ -626,7 +611,7 @@ def _populate_form(field_name: str, explode: boolean, obj: any, get_field_name_f return params -def _serialize_header(explode: bool, obj: any) -> str: +def _serialize_header(explode: bool, obj: Any) -> str: if obj is None: return '' @@ -850,7 +835,7 @@ def list_decode(val: List): def union_encoder(all_encoders: Dict[str, Callable]): - def selective_encoder(val: any): + def selective_encoder(val: Any): if type(val) in all_encoders: return all_encoders[type(val)](val) return val @@ -858,7 +843,7 @@ def selective_encoder(val: any): def union_decoder(all_decoders: List[Callable]): - def selective_decoder(val: any): + def selective_decoder(val: Any): decoded = val for decoder in all_decoders: try: @@ -877,18 +862,18 @@ def override(_, _field_name=name): return override -def _val_to_string(val): +def _val_to_string(val) -> str: if isinstance(val, bool): return str(val).lower() if isinstance(val, datetime): - return val.isoformat().replace('+00:00', 'Z') + return str(val.isoformat().replace('+00:00', 'Z')) if isinstance(val, Enum): return str(val.value) return str(val) -def _populate_from_globals(param_name: str, value: any, param_type: str, gbls: Dict[str, Dict[str, Dict[str, Any]]]): +def _populate_from_globals(param_name: str, value: Any, param_type: str, gbls: Optional[Dict[str, Dict[str, Dict[str, Any]]]]): if value is None and gbls is not None: if 'parameters' in gbls: if param_type in gbls['parameters']: