diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fced1405..1a24ee282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ - **Feature:** add support for Federated Identity Providers - new operations: `CreateFederatedIdentityProvider`, `DeleteServiceFederatedIdentityProvider`, `ListFederatedIdentityProviders`,`PartialUpdateServiceAccountFederatedIdentityProvider` - new models: `CreateFederatedIdentityProviderPayload`, `CreateFederatedIdentityProviderPayloadAssertionsInner`, `CreateFederatedIdentityProviderResponse`, `CreateFederatedIdentityProviderResponseAssertionsInner`, `FederatedListFederatedIdentityProvidersResponse`, `PartialUpdateServiceAccountFederatedIdentityProviderPayload` +- `sqlserverflex`: [v1.1.2](services/sqlserverflex/CHANGELOG.md#v112) + - **Feature:** client now supports UUID and decimal types + - **Bugfix:** timeouts now passed to requests library - `observability`: [v0.13.0](services/observability/CHANGELOG.md#v0130) - **Feature:** manage alert records - New API client methods: `create_alert_record`, `delete_alert_record`, `delete_alert_records`, `get_alert_record`, `list_alert_records`, `update_alert_record`, `partial_update_alert_records` diff --git a/services/sqlserverflex/CHANGELOG.md b/services/sqlserverflex/CHANGELOG.md index e0dbea77a..825df6912 100644 --- a/services/sqlserverflex/CHANGELOG.md +++ b/services/sqlserverflex/CHANGELOG.md @@ -1,3 +1,7 @@ +## v1.1.2 +- **Feature:** client now supports UUID and decimal types +- **Bugfix:** timeouts now passed to requests library + ## v1.1.1 - **Breaking change:** Add region parameter in `ListMetrics` method. Previously the method failed, because the region parameter was missing diff --git a/services/sqlserverflex/oas_commit b/services/sqlserverflex/oas_commit new file mode 100644 index 000000000..e3713dde3 --- /dev/null +++ b/services/sqlserverflex/oas_commit @@ -0,0 +1 @@ +0e64886dd0847341800d7191ed193b75413be998 diff --git a/services/sqlserverflex/pyproject.toml b/services/sqlserverflex/pyproject.toml index 25fd101ff..65c8f145c 100644 --- a/services/sqlserverflex/pyproject.toml +++ b/services/sqlserverflex/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "stackit-sqlserverflex" -version = "v1.1.1" +version = "v1.1.2" description = "STACKIT MSSQL Service API" authors = [{ name = "STACKIT Developer Tools", email = "developer-tools@stackit.cloud" }] requires-python = ">=3.9,<4.0" diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/api_client.py b/services/sqlserverflex/src/stackit/sqlserverflex/api_client.py index 2d129c4d6..c423aefea 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/api_client.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/api_client.py @@ -13,11 +13,13 @@ """ # noqa: E501 import datetime +import decimal import json import mimetypes import os import re import tempfile +import uuid from enum import Enum from typing import Dict, List, Optional, Tuple, Union from urllib.parse import quote @@ -64,8 +66,10 @@ class ApiClient: "bool": bool, "date": datetime.date, "datetime": datetime.datetime, + "decimal": decimal.Decimal, "object": object, } + _pool = None def __init__(self, configuration, header_name=None, header_value=None, cookie=None) -> None: self.config: Configuration = configuration @@ -268,7 +272,7 @@ def response_deserialize( return_data = self.__deserialize_file(response_data) elif response_type is not None: match = None - content_type = response_data.getheader("content-type") + content_type = response_data.headers.get("content-type") if content_type is not None: match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) encoding = match.group(1) if match else "utf-8" @@ -285,7 +289,7 @@ def response_deserialize( return ApiResponse( status_code=response_data.status, data=return_data, - headers=response_data.getheaders(), + headers=response_data.headers, raw_data=response_data.data, ) @@ -297,6 +301,7 @@ def sanitize_for_serialization(self, obj): If obj is str, int, long, float, bool, return directly. If obj is datetime.datetime, datetime.date convert to string in iso8601 format. + If obj is decimal.Decimal return string representation. If obj is list, sanitize each element in the list. If obj is dict, return the dict. If obj is OpenAPI model, return the properties dict. @@ -312,12 +317,16 @@ def sanitize_for_serialization(self, obj): return obj.get_secret_value() elif isinstance(obj, self.PRIMITIVE_TYPES): return obj + elif isinstance(obj, uuid.UUID): + return str(obj) elif isinstance(obj, list): return [self.sanitize_for_serialization(sub_obj) for sub_obj in obj] elif isinstance(obj, tuple): return tuple(self.sanitize_for_serialization(sub_obj) for sub_obj in obj) elif isinstance(obj, (datetime.datetime, datetime.date)): return obj.isoformat() + elif isinstance(obj, decimal.Decimal): + return str(obj) elif isinstance(obj, dict): obj_dict = obj @@ -327,7 +336,7 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - if hasattr(obj, "to_dict") and callable(obj.to_dict): + if hasattr(obj, "to_dict") and callable(getattr(obj, "to_dict")): # noqa: B009 obj_dict = obj.to_dict() else: obj_dict = obj.__dict__ @@ -355,7 +364,7 @@ def deserialize(self, response_text: str, response_type: str, content_type: Opti data = json.loads(response_text) except ValueError: data = response_text - elif re.match(r"^application/(json|[\w!#$&.+-^_]+\+json)\s*(;|$)", content_type, re.IGNORECASE): + elif re.match(r"^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)", content_type, re.IGNORECASE): if response_text == "": data = "" else: @@ -401,12 +410,14 @@ def __deserialize(self, data, klass): if klass in self.PRIMITIVE_TYPES: return self.__deserialize_primitive(data, klass) - elif klass == object: + elif klass is object: return self.__deserialize_object(data) - elif klass == datetime.date: + elif klass is datetime.date: return self.__deserialize_date(data) - elif klass == datetime.datetime: + elif klass is datetime.datetime: return self.__deserialize_datetime(data) + elif klass is decimal.Decimal: + return decimal.Decimal(data) elif issubclass(klass, Enum): return self.__deserialize_enum(data, klass) else: @@ -554,12 +565,14 @@ def __deserialize_file(self, response): os.close(fd) os.remove(path) - content_disposition = response.getheader("Content-Disposition") + content_disposition = response.headers.get("Content-Disposition") if content_disposition: m = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition) if m is None: raise ValueError("Unexpected 'content-disposition' header value") - filename = m.group(1) + filename = os.path.basename(m.group(1)) # Strip any directory traversal + if filename in ("", ".", ".."): # fall back to tmp filename + filename = os.path.basename(path) path = os.path.join(os.path.dirname(path), filename) with open(path, "wb") as f: diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/exceptions.py b/services/sqlserverflex/src/stackit/sqlserverflex/exceptions.py index ed802f3b1..d06b4c1bc 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/exceptions.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/exceptions.py @@ -130,7 +130,7 @@ def __init__( self.body = http_resp.data.decode("utf-8") except Exception: # noqa: S110 pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/__init__.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/__init__.py index 94eafc84a..3edc7e2d6 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/__init__.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from stackit.sqlserverflex.models.acl import ACL from stackit.sqlserverflex.models.backup import Backup diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/backup_list_backups_response_grouped.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/backup_list_backups_response_grouped.py index bdc3bcbba..cead1a3b5 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/backup_list_backups_response_grouped.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/backup_list_backups_response_grouped.py @@ -73,9 +73,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in backups (list) _items = [] if self.backups: - for _item in self.backups: - if _item: - _items.append(_item.to_dict()) + for _item_backups in self.backups: + if _item_backups: + _items.append(_item_backups.to_dict()) _dict["backups"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/host.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/host.py index 684523364..f9af2fb08 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/host.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/host.py @@ -73,9 +73,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in host_metrics (list) _items = [] if self.host_metrics: - for _item in self.host_metrics: - if _item: - _items.append(_item.to_dict()) + for _item_host_metrics in self.host_metrics: + if _item_host_metrics: + _items.append(_item_host_metrics.to_dict()) _dict["hostMetrics"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/host_metric.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/host_metric.py index 11b3801b7..0b148248a 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/host_metric.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/host_metric.py @@ -74,9 +74,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in datapoints (list) _items = [] if self.datapoints: - for _item in self.datapoints: - if _item: - _items.append(_item.to_dict()) + for _item_datapoints in self.datapoints: + if _item_datapoints: + _items.append(_item_datapoints.to_dict()) _dict["datapoints"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_backups_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_backups_response.py index 18d64b154..7c1d6a20e 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_backups_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_backups_response.py @@ -74,9 +74,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in databases (list) _items = [] if self.databases: - for _item in self.databases: - if _item: - _items.append(_item.to_dict()) + for _item_databases in self.databases: + if _item_databases: + _items.append(_item_databases.to_dict()) _dict["databases"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_collations_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_collations_response.py index 128220bc3..867dcf05e 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_collations_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_collations_response.py @@ -72,9 +72,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in collations (list) _items = [] if self.collations: - for _item in self.collations: - if _item: - _items.append(_item.to_dict()) + for _item_collations in self.collations: + if _item_collations: + _items.append(_item_collations.to_dict()) _dict["collations"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_compatibility_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_compatibility_response.py index c8d7c887c..35526a045 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_compatibility_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_compatibility_response.py @@ -74,9 +74,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in compatibilities (list) _items = [] if self.compatibilities: - for _item in self.compatibilities: - if _item: - _items.append(_item.to_dict()) + for _item_compatibilities in self.compatibilities: + if _item_compatibilities: + _items.append(_item_compatibilities.to_dict()) _dict["compatibilities"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_databases_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_databases_response.py index e95c3de69..a5e8ef136 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_databases_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_databases_response.py @@ -72,9 +72,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in databases (list) _items = [] if self.databases: - for _item in self.databases: - if _item: - _items.append(_item.to_dict()) + for _item_databases in self.databases: + if _item_databases: + _items.append(_item_databases.to_dict()) _dict["databases"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_flavors_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_flavors_response.py index cf77398a5..687444510 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_flavors_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_flavors_response.py @@ -72,9 +72,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in flavors (list) _items = [] if self.flavors: - for _item in self.flavors: - if _item: - _items.append(_item.to_dict()) + for _item_flavors in self.flavors: + if _item_flavors: + _items.append(_item_flavors.to_dict()) _dict["flavors"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_instances_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_instances_response.py index 9fdd74b9f..493abbfdf 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_instances_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_instances_response.py @@ -73,9 +73,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in items (list) _items = [] if self.items: - for _item in self.items: - if _item: - _items.append(_item.to_dict()) + for _item_items in self.items: + if _item_items: + _items.append(_item_items.to_dict()) _dict["items"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_metrics_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_metrics_response.py index 72404bb8a..1f2bc02b0 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_metrics_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_metrics_response.py @@ -72,9 +72,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in hosts (list) _items = [] if self.hosts: - for _item in self.hosts: - if _item: - _items.append(_item.to_dict()) + for _item_hosts in self.hosts: + if _item_hosts: + _items.append(_item_hosts.to_dict()) _dict["hosts"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_restore_jobs_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_restore_jobs_response.py index 9aeceb3da..39d2433c3 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_restore_jobs_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_restore_jobs_response.py @@ -72,9 +72,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in running_restores (list) _items = [] if self.running_restores: - for _item in self.running_restores: - if _item: - _items.append(_item.to_dict()) + for _item_running_restores in self.running_restores: + if _item_running_restores: + _items.append(_item_running_restores.to_dict()) _dict["runningRestores"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_users_response.py b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_users_response.py index 7edfbf5bc..58bf780b8 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/models/list_users_response.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/models/list_users_response.py @@ -73,9 +73,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in items (list) _items = [] if self.items: - for _item in self.items: - if _item: - _items.append(_item.to_dict()) + for _item_items in self.items: + if _item_items: + _items.append(_item_items.to_dict()) _dict["items"] = _items return _dict diff --git a/services/sqlserverflex/src/stackit/sqlserverflex/rest.py b/services/sqlserverflex/src/stackit/sqlserverflex/rest.py index 412e0d33a..d827c66bd 100644 --- a/services/sqlserverflex/src/stackit/sqlserverflex/rest.py +++ b/services/sqlserverflex/src/stackit/sqlserverflex/rest.py @@ -39,12 +39,17 @@ def read(self): self.data = self.response.content return self.data + @property + def headers(self): + """Returns a dictionary of response headers.""" + return self.response.headers + def getheaders(self): - """Returns a dictionary of the response headers.""" + """Returns a dictionary of the response headers; use ``headers`` instead.""" return self.response.headers def getheader(self, name, default=None): - """Returns a given response header.""" + """Returns a given response header; use ``headers.get()`` instead.""" return self.response.headers.get(name, default) @@ -94,6 +99,7 @@ def request(self, method, url, headers=None, body=None, post_params=None, _reque url, data=request_body, headers=headers, + timeout=_request_timeout, ) elif content_type == "application/x-www-form-urlencoded": r = self.session.request( @@ -101,6 +107,7 @@ def request(self, method, url, headers=None, body=None, post_params=None, _reque url, params=post_params, headers=headers, + timeout=_request_timeout, ) elif content_type == "multipart/form-data": # must del headers['Content-Type'], or the correct @@ -114,6 +121,7 @@ def request(self, method, url, headers=None, body=None, post_params=None, _reque url, files=post_params, headers=headers, + timeout=_request_timeout, ) # Pass a `string` parameter directly in the body to support # other content types than JSON when `body` argument is @@ -124,10 +132,17 @@ def request(self, method, url, headers=None, body=None, post_params=None, _reque url, data=body, headers=headers, + timeout=_request_timeout, ) elif headers["Content-Type"].startswith("text/") and isinstance(body, bool): request_body = "true" if body else "false" - r = self.session.request(method, url, data=request_body, headers=headers) + r = self.session.request( + method, + url, + data=request_body, + headers=headers, + timeout=_request_timeout, + ) else: # Cannot generate the request from given parameters msg = """Cannot prepare a request message for provided @@ -141,6 +156,7 @@ def request(self, method, url, headers=None, body=None, post_params=None, _reque url, params={}, headers=headers, + timeout=_request_timeout, ) except requests.exceptions.SSLError as e: msg = "\n".join([type(e).__name__, str(e)])