diff --git a/services/dns/oas_commit b/services/dns/oas_commit new file mode 100644 index 000000000..e3713dde3 --- /dev/null +++ b/services/dns/oas_commit @@ -0,0 +1 @@ +0e64886dd0847341800d7191ed193b75413be998 diff --git a/services/dns/src/stackit/dns/api_client.py b/services/dns/src/stackit/dns/api_client.py index 8d1f0602d..15a2051a8 100644 --- a/services/dns/src/stackit/dns/api_client.py +++ b/services/dns/src/stackit/dns/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")): 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/dns/src/stackit/dns/exceptions.py b/services/dns/src/stackit/dns/exceptions.py index c5914dad8..d1a664767 100644 --- a/services/dns/src/stackit/dns/exceptions.py +++ b/services/dns/src/stackit/dns/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/dns/src/stackit/dns/models/__init__.py b/services/dns/src/stackit/dns/models/__init__.py index c07e4bcb9..29b7cd756 100644 --- a/services/dns/src/stackit/dns/models/__init__.py +++ b/services/dns/src/stackit/dns/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from stackit.dns.models.clone_zone_payload import CloneZonePayload from stackit.dns.models.create_label_payload import CreateLabelPayload diff --git a/services/dns/src/stackit/dns/models/create_record_set_payload.py b/services/dns/src/stackit/dns/models/create_record_set_payload.py index a12bdbede..efadaca3a 100644 --- a/services/dns/src/stackit/dns/models/create_record_set_payload.py +++ b/services/dns/src/stackit/dns/models/create_record_set_payload.py @@ -119,9 +119,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in records (list) _items = [] if self.records: - for _item in self.records: - if _item: - _items.append(_item.to_dict()) + for _item_records in self.records: + if _item_records: + _items.append(_item_records.to_dict()) _dict["records"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/import_record_sets_payload.py b/services/dns/src/stackit/dns/models/import_record_sets_payload.py index 717e9f7eb..031165514 100644 --- a/services/dns/src/stackit/dns/models/import_record_sets_payload.py +++ b/services/dns/src/stackit/dns/models/import_record_sets_payload.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 rr_sets (list) _items = [] if self.rr_sets: - for _item in self.rr_sets: - if _item: - _items.append(_item.to_dict()) + for _item_rr_sets in self.rr_sets: + if _item_rr_sets: + _items.append(_item_rr_sets.to_dict()) _dict["rrSets"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/list_labels_response.py b/services/dns/src/stackit/dns/models/list_labels_response.py index 6b803fadb..6f2440f2d 100644 --- a/services/dns/src/stackit/dns/models/list_labels_response.py +++ b/services/dns/src/stackit/dns/models/list_labels_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 labels (list) _items = [] if self.labels: - for _item in self.labels: - if _item: - _items.append(_item.to_dict()) + for _item_labels in self.labels: + if _item_labels: + _items.append(_item_labels.to_dict()) _dict["labels"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/list_record_sets_response.py b/services/dns/src/stackit/dns/models/list_record_sets_response.py index 536a1aab1..36ea48e6c 100644 --- a/services/dns/src/stackit/dns/models/list_record_sets_response.py +++ b/services/dns/src/stackit/dns/models/list_record_sets_response.py @@ -76,9 +76,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in rr_sets (list) _items = [] if self.rr_sets: - for _item in self.rr_sets: - if _item: - _items.append(_item.to_dict()) + for _item_rr_sets in self.rr_sets: + if _item_rr_sets: + _items.append(_item_rr_sets.to_dict()) _dict["rrSets"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/list_zones_response.py b/services/dns/src/stackit/dns/models/list_zones_response.py index 705e3e163..6c22da3c4 100644 --- a/services/dns/src/stackit/dns/models/list_zones_response.py +++ b/services/dns/src/stackit/dns/models/list_zones_response.py @@ -76,9 +76,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in zones (list) _items = [] if self.zones: - for _item in self.zones: - if _item: - _items.append(_item.to_dict()) + for _item_zones in self.zones: + if _item_zones: + _items.append(_item_zones.to_dict()) _dict["zones"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/partial_update_record_payload.py b/services/dns/src/stackit/dns/models/partial_update_record_payload.py index 69411f977..633710fcf 100644 --- a/services/dns/src/stackit/dns/models/partial_update_record_payload.py +++ b/services/dns/src/stackit/dns/models/partial_update_record_payload.py @@ -80,9 +80,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in records (list) _items = [] if self.records: - for _item in self.records: - if _item: - _items.append(_item.to_dict()) + for _item_records in self.records: + if _item_records: + _items.append(_item_records.to_dict()) _dict["records"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/partial_update_record_set_payload.py b/services/dns/src/stackit/dns/models/partial_update_record_set_payload.py index 31126f6d9..9c718bc3d 100644 --- a/services/dns/src/stackit/dns/models/partial_update_record_set_payload.py +++ b/services/dns/src/stackit/dns/models/partial_update_record_set_payload.py @@ -81,9 +81,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in records (list) _items = [] if self.records: - for _item in self.records: - if _item: - _items.append(_item.to_dict()) + for _item_records in self.records: + if _item_records: + _items.append(_item_records.to_dict()) _dict["records"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/record_set.py b/services/dns/src/stackit/dns/models/record_set.py index b1f381252..974e033fc 100644 --- a/services/dns/src/stackit/dns/models/record_set.py +++ b/services/dns/src/stackit/dns/models/record_set.py @@ -167,9 +167,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in records (list) _items = [] if self.records: - for _item in self.records: - if _item: - _items.append(_item.to_dict()) + for _item_records in self.records: + if _item_records: + _items.append(_item_records.to_dict()) _dict["records"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/zone.py b/services/dns/src/stackit/dns/models/zone.py index f0e07b7c7..11fa9b662 100644 --- a/services/dns/src/stackit/dns/models/zone.py +++ b/services/dns/src/stackit/dns/models/zone.py @@ -197,9 +197,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in labels (list) _items = [] if self.labels: - for _item in self.labels: - if _item: - _items.append(_item.to_dict()) + for _item_labels in self.labels: + if _item_labels: + _items.append(_item_labels.to_dict()) _dict["labels"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/zone_data_exchange.py b/services/dns/src/stackit/dns/models/zone_data_exchange.py index a938d73f1..470e252ab 100644 --- a/services/dns/src/stackit/dns/models/zone_data_exchange.py +++ b/services/dns/src/stackit/dns/models/zone_data_exchange.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 rr_sets (list) _items = [] if self.rr_sets: - for _item in self.rr_sets: - if _item: - _items.append(_item.to_dict()) + for _item_rr_sets in self.rr_sets: + if _item_rr_sets: + _items.append(_item_rr_sets.to_dict()) _dict["rrSets"] = _items return _dict diff --git a/services/dns/src/stackit/dns/models/zone_models_import_zone_json.py b/services/dns/src/stackit/dns/models/zone_models_import_zone_json.py index 7484b4686..72be11a07 100644 --- a/services/dns/src/stackit/dns/models/zone_models_import_zone_json.py +++ b/services/dns/src/stackit/dns/models/zone_models_import_zone_json.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 rr_sets (list) _items = [] if self.rr_sets: - for _item in self.rr_sets: - if _item: - _items.append(_item.to_dict()) + for _item_rr_sets in self.rr_sets: + if _item_rr_sets: + _items.append(_item_rr_sets.to_dict()) _dict["rrSets"] = _items return _dict diff --git a/services/dns/src/stackit/dns/rest.py b/services/dns/src/stackit/dns/rest.py index dfda9f56f..e7b0fa87a 100644 --- a/services/dns/src/stackit/dns/rest.py +++ b/services/dns/src/stackit/dns/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)])