diff --git a/.github/workflows/_common.yml b/.github/workflows/_common.yml index ceabd1b1..b78da042 100644 --- a/.github/workflows/_common.yml +++ b/.github/workflows/_common.yml @@ -13,7 +13,7 @@ on: jobs: lint: name: Lint ${{ inputs.package-name }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ./.github/workflows/composite/lint-sdk diff --git a/.github/workflows/_generate.yml b/.github/workflows/_generate.yml index 3d39fb48..58a88e9b 100644 --- a/.github/workflows/_generate.yml +++ b/.github/workflows/_generate.yml @@ -14,7 +14,7 @@ on: jobs: generate: name: Generate ${{ inputs.package-name }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ./.github/workflows/composite/generate-sdk diff --git a/.github/workflows/_publish.yml b/.github/workflows/_publish.yml index 3439b47e..0dae71bd 100644 --- a/.github/workflows/_publish.yml +++ b/.github/workflows/_publish.yml @@ -16,7 +16,7 @@ on: jobs: publish-python-packages: name: Publish ${{ inputs.package_to_publish }} to PyPI - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 41b3fb84..8b7a2baf 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -19,7 +19,7 @@ on: jobs: test: name: Test ${{ inputs.package-name }} py v ${{ matrix.python-version }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest services: mockserver: image: mockserver/mockserver:5.15.0 @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ '3.7', '3.12' ] + python-version: [ '3.10', '3.14' ] steps: - uses: actions/checkout@v3 - uses: ./.github/workflows/composite/test-sdk diff --git a/.github/workflows/composite/setup-python/action.yml b/.github/workflows/composite/setup-python/action.yml index c44a0d27..16184aee 100644 --- a/.github/workflows/composite/setup-python/action.yml +++ b/.github/workflows/composite/setup-python/action.yml @@ -4,7 +4,7 @@ inputs: python-version: description: 'Version of Python to setup.' required: false - default: '3.7' + default: '3.10' runs: using: "composite" steps: diff --git a/.github/workflows/generate-all.yml b/.github/workflows/generate-all.yml index 0c486e43..8ec1091e 100644 --- a/.github/workflows/generate-all.yml +++ b/.github/workflows/generate-all.yml @@ -16,7 +16,7 @@ jobs: prerequisite: name: Prerequisite for Generation if: github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/feature') - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Prerequisite run: | @@ -86,7 +86,7 @@ jobs: # Push generated code push-changes: name: Push Changes - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: - generate-bmcapi - generate-ranchersolutionapi diff --git a/.github/workflows/validate-all.yml b/.github/workflows/validate-all.yml index 96528257..131d7191 100644 --- a/.github/workflows/validate-all.yml +++ b/.github/workflows/validate-all.yml @@ -80,7 +80,7 @@ jobs: - build-and-test-invoicingapi - build-and-test-paymentsapi - run-generic-tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest if: always() steps: - name: Download Artifacts diff --git a/.gitignore b/.gitignore index 3db0686a..927e29fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ Test Results/ **/test-reports/ __pycache__ -*.egg-info \ No newline at end of file +*.egg-info +.venv/ \ No newline at end of file diff --git a/openapitools.json b/openapitools.json index 64f2cbb5..29399d30 100644 --- a/openapitools.json +++ b/openapitools.json @@ -2,6 +2,6 @@ "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", "spaces": 2, "generator-cli": { - "version": "7.2.0" + "version": "7.20.0" } } diff --git a/pnap_audit_api/README.md b/pnap_audit_api/README.md index b3cb2bb1..dd015a22 100644 --- a/pnap_audit_api/README.md +++ b/pnap_audit_api/README.md @@ -12,13 +12,13 @@ Knowledge base articles to help you can be found This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0 -- Package version: 2.0.4 +- Package version: 2.0.5 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -48,9 +48,16 @@ Then import the package: import pnap_audit_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_audit_api from pnap_audit_api.rest import ApiException from pprint import pprint @@ -76,7 +83,7 @@ with pnap_audit_api.ApiClient(configuration) as api_client: var_from = '2021-04-27T16:24:57.123Z' # datetime | From the date and time (inclusive) to filter event log records by. (optional) to = '2021-04-29T16:24:57.123Z' # datetime | To the date and time (inclusive) to filter event log records by. (optional) limit = 10 # int | Limit the number of records returned. (optional) - order = 'ASC' # str | Ordering of the event's time. SortBy can be introduced later on. (optional) (default to 'ASC') + order = ASC # str | Ordering of the event's time. SortBy can be introduced later on. (optional) (default to ASC) username = 'johnd@phoenixnap.com' # str | The username that did the actions. (optional) verb = 'verb_example' # str | The HTTP verb corresponding to the action. (optional) uri = '/ams/v1/clients/12345' # str | The request uri. (optional) @@ -107,6 +114,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -143,4 +151,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_audit_api/docs/Error.md b/pnap_audit_api/docs/Error.md index 2b67054a..d8fc4ba9 100644 --- a/pnap_audit_api/docs/Error.md +++ b/pnap_audit_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_audit_api/docs/Event.md b/pnap_audit_api/docs/Event.md index c08aaa3f..d3128f95 100644 --- a/pnap_audit_api/docs/Event.md +++ b/pnap_audit_api/docs/Event.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of Event from a JSON string event_instance = Event.from_json(json) # print the JSON string representation of the object -print Event.to_json() +print(Event.to_json()) # convert the object into a dict event_dict = event_instance.to_dict() # create an instance of Event from a dict -event_form_dict = event.from_dict(event_dict) +event_from_dict = Event.from_dict(event_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_audit_api/docs/EventsApi.md b/pnap_audit_api/docs/EventsApi.md index caa15bab..fb86d2ff 100644 --- a/pnap_audit_api/docs/EventsApi.md +++ b/pnap_audit_api/docs/EventsApi.md @@ -19,8 +19,6 @@ Retrieves the event logs for given time period. All date & times are in UTC. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_audit_api from pnap_audit_api.models.event import Event from pnap_audit_api.rest import ApiException @@ -46,7 +44,7 @@ with pnap_audit_api.ApiClient(configuration) as api_client: var_from = '2021-04-27T16:24:57.123Z' # datetime | From the date and time (inclusive) to filter event log records by. (optional) to = '2021-04-29T16:24:57.123Z' # datetime | To the date and time (inclusive) to filter event log records by. (optional) limit = 10 # int | Limit the number of records returned. (optional) - order = 'ASC' # str | Ordering of the event's time. SortBy can be introduced later on. (optional) (default to 'ASC') + order = ASC # str | Ordering of the event's time. SortBy can be introduced later on. (optional) (default to ASC) username = 'johnd@phoenixnap.com' # str | The username that did the actions. (optional) verb = 'verb_example' # str | The HTTP verb corresponding to the action. (optional) uri = '/ams/v1/clients/12345' # str | The request uri. (optional) @@ -70,7 +68,7 @@ Name | Type | Description | Notes **var_from** | **datetime**| From the date and time (inclusive) to filter event log records by. | [optional] **to** | **datetime**| To the date and time (inclusive) to filter event log records by. | [optional] **limit** | **int**| Limit the number of records returned. | [optional] - **order** | **str**| Ordering of the event's time. SortBy can be introduced later on. | [optional] [default to 'ASC'] + **order** | **str**| Ordering of the event's time. SortBy can be introduced later on. | [optional] [default to ASC] **username** | **str**| The username that did the actions. | [optional] **verb** | **str**| The HTTP verb corresponding to the action. | [optional] **uri** | **str**| The request uri. | [optional] diff --git a/pnap_audit_api/docs/UserInfo.md b/pnap_audit_api/docs/UserInfo.md index cfb51094..d370dfd7 100644 --- a/pnap_audit_api/docs/UserInfo.md +++ b/pnap_audit_api/docs/UserInfo.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of UserInfo from a JSON string user_info_instance = UserInfo.from_json(json) # print the JSON string representation of the object -print UserInfo.to_json() +print(UserInfo.to_json()) # convert the object into a dict user_info_dict = user_info_instance.to_dict() # create an instance of UserInfo from a dict -user_info_form_dict = user_info.from_dict(user_info_dict) +user_info_from_dict = UserInfo.from_dict(user_info_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_audit_api/pnap_audit_api/__init__.py b/pnap_audit_api/pnap_audit_api/__init__.py index 592b204b..68eb3c63 100644 --- a/pnap_audit_api/pnap_audit_api/__init__.py +++ b/pnap_audit_api/pnap_audit_api/__init__.py @@ -15,23 +15,41 @@ """ # noqa: E501 -__version__ = "2.0.4" +__version__ = "2.0.5" + +# Define package exports +__all__ = [ + "EventsApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "Error", + "Event", + "UserInfo", +] # import apis into sdk package -from pnap_audit_api.api.events_api import EventsApi +from pnap_audit_api.api.events_api import EventsApi as EventsApi # import ApiClient -from pnap_audit_api.api_response import ApiResponse -from pnap_audit_api.api_client import ApiClient -from pnap_audit_api.configuration import Configuration -from pnap_audit_api.exceptions import OpenApiException -from pnap_audit_api.exceptions import ApiTypeError -from pnap_audit_api.exceptions import ApiValueError -from pnap_audit_api.exceptions import ApiKeyError -from pnap_audit_api.exceptions import ApiAttributeError -from pnap_audit_api.exceptions import ApiException +from pnap_audit_api.api_response import ApiResponse as ApiResponse +from pnap_audit_api.api_client import ApiClient as ApiClient +from pnap_audit_api.configuration import Configuration as Configuration +from pnap_audit_api.exceptions import OpenApiException as OpenApiException +from pnap_audit_api.exceptions import ApiTypeError as ApiTypeError +from pnap_audit_api.exceptions import ApiValueError as ApiValueError +from pnap_audit_api.exceptions import ApiKeyError as ApiKeyError +from pnap_audit_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_audit_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_audit_api.models.error import Error -from pnap_audit_api.models.event import Event -from pnap_audit_api.models.user_info import UserInfo +from pnap_audit_api.models.error import Error as Error +from pnap_audit_api.models.event import Event as Event +from pnap_audit_api.models.user_info import UserInfo as UserInfo + diff --git a/pnap_audit_api/pnap_audit_api/api/events_api.py b/pnap_audit_api/pnap_audit_api/api/events_api.py index e8d41cce..abf75903 100644 --- a/pnap_audit_api/pnap_audit_api/api/events_api.py +++ b/pnap_audit_api/pnap_audit_api/api/events_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Audit Log API @@ -13,28 +11,18 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from datetime import datetime - -from pydantic import StrictInt, StrictStr, field_validator +from datetime import datetime +from pydantic import Field, StrictInt, StrictStr, field_validator from typing import List, Optional - +from typing_extensions import Annotated from pnap_audit_api.models.event import Event -from pnap_audit_api.api_client import ApiClient +from pnap_audit_api.api_client import ApiClient, RequestSerialized from pnap_audit_api.api_response import ApiResponse from pnap_audit_api.rest import RESTResponseType @@ -349,7 +337,7 @@ def _events_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -360,7 +348,9 @@ def _events_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -417,11 +407,12 @@ def _events_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting diff --git a/pnap_audit_api/pnap_audit_api/api_client.py b/pnap_audit_api/pnap_audit_api/api_client.py index 99164162..c8620c29 100644 --- a/pnap_audit_api/pnap_audit_api/api_client.py +++ b/pnap_audit_api/pnap_audit_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Audit Log API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_audit_api.configuration import Configuration -from pnap_audit_api.api_response import ApiResponse +from pnap_audit_api.api_response import ApiResponse, T as ApiResponseT import pnap_audit_api.models from pnap_audit_api import rest from pnap_audit_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_audit_api/2.0.4" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_audit_api/2.0.5" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_audit_api/2.0.4" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_audit_api/2.0.5" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_audit_api/pnap_audit_api/api_response.py b/pnap_audit_api/pnap_audit_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_audit_api/pnap_audit_api/api_response.py +++ b/pnap_audit_api/pnap_audit_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_audit_api/pnap_audit_api/configuration.py b/pnap_audit_api/pnap_audit_api/configuration.py index cbb5ba94..4744f151 100644 --- a/pnap_audit_api/pnap_audit_api/configuration.py +++ b/pnap_audit_api/pnap_audit_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Audit Log API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/audit/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0\n"\ - "SDK Package Version: 2.0.4".\ + "SDK Package Version: 2.0.5".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_audit_api/pnap_audit_api/exceptions.py b/pnap_audit_api/pnap_audit_api/exceptions.py index 44f88565..dcb3f2d5 100644 --- a/pnap_audit_api/pnap_audit_api/exceptions.py +++ b/pnap_audit_api/pnap_audit_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Audit Log API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_audit_api/pnap_audit_api/models/__init__.py b/pnap_audit_api/pnap_audit_api/models/__init__.py index f1f49f0a..5d928cd6 100644 --- a/pnap_audit_api/pnap_audit_api/models/__init__.py +++ b/pnap_audit_api/pnap_audit_api/models/__init__.py @@ -13,8 +13,8 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_audit_api.models.error import Error from pnap_audit_api.models.event import Event from pnap_audit_api.models.user_info import UserInfo + diff --git a/pnap_audit_api/pnap_audit_api/models/error.py b/pnap_audit_api/pnap_audit_api/models/error.py index fce30eb2..aeb265b0 100644 --- a/pnap_audit_api/pnap_audit_api/models/error.py +++ b/pnap_audit_api/pnap_audit_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_audit_api/pnap_audit_api/models/event.py b/pnap_audit_api/pnap_audit_api/models/event.py index 00613f52..2b4e2477 100644 --- a/pnap_audit_api/pnap_audit_api/models/event.py +++ b/pnap_audit_api/pnap_audit_api/models/event.py @@ -19,14 +19,11 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from pnap_audit_api.models.user_info import UserInfo -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Event(BaseModel): """ @@ -38,11 +35,11 @@ class Event(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["name", "timestamp", "userInfo"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +52,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Event from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,11 +67,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of user_info @@ -88,7 +87,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Event from a dict""" if obj is None: return None @@ -99,7 +98,7 @@ def from_dict(cls, obj: Dict) -> Self: _obj = cls.model_validate({ "name": obj.get("name"), "timestamp": obj.get("timestamp"), - "userInfo": UserInfo.from_dict(obj.get("userInfo")) if obj.get("userInfo") is not None else None + "userInfo": UserInfo.from_dict(obj["userInfo"]) if obj.get("userInfo") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_audit_api/pnap_audit_api/models/user_info.py b/pnap_audit_api/pnap_audit_api/models/user_info.py index fc3a4cd2..97329dfe 100644 --- a/pnap_audit_api/pnap_audit_api/models/user_info.py +++ b/pnap_audit_api/pnap_audit_api/models/user_info.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class UserInfo(BaseModel): """ @@ -37,11 +33,11 @@ class UserInfo(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["accountId", "clientId", "username"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of UserInfo from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of UserInfo from a dict""" if obj is None: return None diff --git a/pnap_audit_api/pnap_audit_api/rest.py b/pnap_audit_api/pnap_audit_api/rest.py index 3c8b0e0b..455ffd79 100644 --- a/pnap_audit_api/pnap_audit_api/rest.py +++ b/pnap_audit_api/pnap_audit_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_audit_api/pnap_audit_api/version.py b/pnap_audit_api/pnap_audit_api/version.py index c756f9c5..09091e00 100644 --- a/pnap_audit_api/pnap_audit_api/version.py +++ b/pnap_audit_api/pnap_audit_api/version.py @@ -1 +1 @@ -VERSION = "2.0.4" \ No newline at end of file +VERSION = "2.0.5" \ No newline at end of file diff --git a/pnap_audit_api/pyproject.toml b/pnap_audit_api/pyproject.toml index c400c3e8..f5a24d70 100644 --- a/pnap_audit_api/pyproject.toml +++ b/pnap_audit_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_audit_api" -version = "2.0.4" +version = "2.0.5" description = "Audit Log API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Audit Log API"] -include = ["pnap_audit_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_audit_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_audit_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_audit_api/requirements.txt b/pnap_audit_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_audit_api/requirements.txt +++ b/pnap_audit_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_audit_api/setup.py b/pnap_audit_api/setup.py index 97ab10e7..693035f0 100644 --- a/pnap_audit_api/setup.py +++ b/pnap_audit_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Audit Log API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_audit_api" -VERSION = "2.0.4" -PYTHON_REQUIRES = ">=3.7" +VERSION = "2.0.5" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ The Audit Logs API lets you read audit log entries and track API calls or activities in the Bare Metal Cloud Portal.<br> <br> <span class='pnap-api-knowledge-base-link'> Knowledge base articles to help you can be found <a href='https://phoenixnap.com/kb/bmc-server-management-via-api#audit-log-api' target='_blank'>here</a> </span><br> <br> <b>All URLs are relative to (https://api.phoenixnap.com/audit/v1/)</b> """, # noqa: E501 package_data={"pnap_audit_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_bmc_api/README.md b/pnap_bmc_api/README.md index 7743c610..7843b1ed 100644 --- a/pnap_bmc_api/README.md +++ b/pnap_bmc_api/README.md @@ -14,13 +14,13 @@ Knowledge base articles to help you can be found This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 0.1 -- Package version: 2.2.1 +- Package version: 2.3.0 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -50,9 +50,16 @@ Then import the package: import pnap_bmc_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_bmc_api from pnap_bmc_api.rest import ApiException from pprint import pprint @@ -102,6 +109,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -129,6 +137,7 @@ Class | Method | HTTP request | Description *ServersApi* | [**servers_server_id_actions_reserve_post**](docs/ServersApi.md#servers_server_id_actions_reserve_post) | **POST** /servers/{serverId}/actions/reserve | Reserve server. *ServersApi* | [**servers_server_id_actions_reset_post**](docs/ServersApi.md#servers_server_id_actions_reset_post) | **POST** /servers/{serverId}/actions/reset | Reset server. *ServersApi* | [**servers_server_id_actions_shutdown_post**](docs/ServersApi.md#servers_server_id_actions_shutdown_post) | **POST** /servers/{serverId}/actions/shutdown | Shutdown server. +*ServersApi* | [**servers_server_id_actions_transfer_reservation**](docs/ServersApi.md#servers_server_id_actions_transfer_reservation) | **POST** /servers/{serverId}/actions/transfer-reservation | Transfer server reservation. *ServersApi* | [**servers_server_id_delete**](docs/ServersApi.md#servers_server_id_delete) | **DELETE** /servers/{serverId} | Delete server. *ServersApi* | [**servers_server_id_get**](docs/ServersApi.md#servers_server_id_get) | **GET** /servers/{serverId} | Get server. *ServersApi* | [**servers_server_id_ip_blocks_ip_block_id_delete**](docs/ServersApi.md#servers_server_id_ip_blocks_ip_block_id_delete) | **DELETE** /servers/{serverId}/network-configuration/ip-block-configurations/ip-blocks/{ipBlockId} | Unassign IP Block from Server. @@ -167,6 +176,7 @@ Class | Method | HTTP request | Description - [QuotaEditLimitRequest](docs/QuotaEditLimitRequest.md) - [QuotaEditLimitRequestDetails](docs/QuotaEditLimitRequestDetails.md) - [RelinquishIpBlock](docs/RelinquishIpBlock.md) + - [ReservationTransferDetails](docs/ReservationTransferDetails.md) - [ResetResult](docs/ResetResult.md) - [Server](docs/Server.md) - [ServerCreate](docs/ServerCreate.md) @@ -206,4 +216,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_bmc_api/docs/ActionResult.md b/pnap_bmc_api/docs/ActionResult.md index 945e6545..6ac44483 100644 --- a/pnap_bmc_api/docs/ActionResult.md +++ b/pnap_bmc_api/docs/ActionResult.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of ActionResult from a JSON string action_result_instance = ActionResult.from_json(json) # print the JSON string representation of the object -print ActionResult.to_json() +print(ActionResult.to_json()) # convert the object into a dict action_result_dict = action_result_instance.to_dict() # create an instance of ActionResult from a dict -action_result_form_dict = action_result.from_dict(action_result_dict) +action_result_from_dict = ActionResult.from_dict(action_result_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/DeleteResult.md b/pnap_bmc_api/docs/DeleteResult.md index 0c144f13..516d90dd 100644 --- a/pnap_bmc_api/docs/DeleteResult.md +++ b/pnap_bmc_api/docs/DeleteResult.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of DeleteResult from a JSON string delete_result_instance = DeleteResult.from_json(json) # print the JSON string representation of the object -print DeleteResult.to_json() +print(DeleteResult.to_json()) # convert the object into a dict delete_result_dict = delete_result_instance.to_dict() # create an instance of DeleteResult from a dict -delete_result_form_dict = delete_result.from_dict(delete_result_dict) +delete_result_from_dict = DeleteResult.from_dict(delete_result_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/DeleteSshKeyResult.md b/pnap_bmc_api/docs/DeleteSshKeyResult.md index ad600a6e..9ac5359d 100644 --- a/pnap_bmc_api/docs/DeleteSshKeyResult.md +++ b/pnap_bmc_api/docs/DeleteSshKeyResult.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of DeleteSshKeyResult from a JSON string delete_ssh_key_result_instance = DeleteSshKeyResult.from_json(json) # print the JSON string representation of the object -print DeleteSshKeyResult.to_json() +print(DeleteSshKeyResult.to_json()) # convert the object into a dict delete_ssh_key_result_dict = delete_ssh_key_result_instance.to_dict() # create an instance of DeleteSshKeyResult from a dict -delete_ssh_key_result_form_dict = delete_ssh_key_result.from_dict(delete_ssh_key_result_dict) +delete_ssh_key_result_from_dict = DeleteSshKeyResult.from_dict(delete_ssh_key_result_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/Error.md b/pnap_bmc_api/docs/Error.md index 3ecca12c..c432ae74 100644 --- a/pnap_bmc_api/docs/Error.md +++ b/pnap_bmc_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/EsxiDatastoreConfiguration.md b/pnap_bmc_api/docs/EsxiDatastoreConfiguration.md index 610ec137..05ccde4d 100644 --- a/pnap_bmc_api/docs/EsxiDatastoreConfiguration.md +++ b/pnap_bmc_api/docs/EsxiDatastoreConfiguration.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of EsxiDatastoreConfiguration from a JSON string esxi_datastore_configuration_instance = EsxiDatastoreConfiguration.from_json(json) # print the JSON string representation of the object -print EsxiDatastoreConfiguration.to_json() +print(EsxiDatastoreConfiguration.to_json()) # convert the object into a dict esxi_datastore_configuration_dict = esxi_datastore_configuration_instance.to_dict() # create an instance of EsxiDatastoreConfiguration from a dict -esxi_datastore_configuration_form_dict = esxi_datastore_configuration.from_dict(esxi_datastore_configuration_dict) +esxi_datastore_configuration_from_dict = EsxiDatastoreConfiguration.from_dict(esxi_datastore_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/EsxiOsConfiguration.md b/pnap_bmc_api/docs/EsxiOsConfiguration.md index 5e0cd970..758f1fc2 100644 --- a/pnap_bmc_api/docs/EsxiOsConfiguration.md +++ b/pnap_bmc_api/docs/EsxiOsConfiguration.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of EsxiOsConfiguration from a JSON string esxi_os_configuration_instance = EsxiOsConfiguration.from_json(json) # print the JSON string representation of the object -print EsxiOsConfiguration.to_json() +print(EsxiOsConfiguration.to_json()) # convert the object into a dict esxi_os_configuration_dict = esxi_os_configuration_instance.to_dict() # create an instance of EsxiOsConfiguration from a dict -esxi_os_configuration_form_dict = esxi_os_configuration.from_dict(esxi_os_configuration_dict) +esxi_os_configuration_from_dict = EsxiOsConfiguration.from_dict(esxi_os_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/GpuConfiguration.md b/pnap_bmc_api/docs/GpuConfiguration.md index 15ae5c57..3d75fc16 100644 --- a/pnap_bmc_api/docs/GpuConfiguration.md +++ b/pnap_bmc_api/docs/GpuConfiguration.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of GpuConfiguration from a JSON string gpu_configuration_instance = GpuConfiguration.from_json(json) # print the JSON string representation of the object -print GpuConfiguration.to_json() +print(GpuConfiguration.to_json()) # convert the object into a dict gpu_configuration_dict = gpu_configuration_instance.to_dict() # create an instance of GpuConfiguration from a dict -gpu_configuration_form_dict = gpu_configuration.from_dict(gpu_configuration_dict) +gpu_configuration_from_dict = GpuConfiguration.from_dict(gpu_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/IpBlocksConfiguration.md b/pnap_bmc_api/docs/IpBlocksConfiguration.md index 562b63dd..f88bfb61 100644 --- a/pnap_bmc_api/docs/IpBlocksConfiguration.md +++ b/pnap_bmc_api/docs/IpBlocksConfiguration.md @@ -7,7 +7,7 @@ The IP blocks to assign to this server. This is an exclusive allocation, Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **configuration_type** | **str** | (Write-only) Determines the approach for configuring IP blocks for the server being provisioned. If PURCHASE_NEW is selected, the smallest supported range, depending on the operating system, is allocated to the server. | [optional] [default to 'PURCHASE_NEW'] -**ip_blocks** | [**List[ServerIpBlock]**](ServerIpBlock.md) | Used to specify the previously purchased IP blocks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType. | [optional] +**ip_blocks** | [**List[ServerIpBlock]**](ServerIpBlock.md) | Used for specifying the previously purchased IPv4 blocks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType. | [optional] ## Example @@ -19,12 +19,12 @@ json = "{}" # create an instance of IpBlocksConfiguration from a JSON string ip_blocks_configuration_instance = IpBlocksConfiguration.from_json(json) # print the JSON string representation of the object -print IpBlocksConfiguration.to_json() +print(IpBlocksConfiguration.to_json()) # convert the object into a dict ip_blocks_configuration_dict = ip_blocks_configuration_instance.to_dict() # create an instance of IpBlocksConfiguration from a dict -ip_blocks_configuration_form_dict = ip_blocks_configuration.from_dict(ip_blocks_configuration_dict) +ip_blocks_configuration_from_dict = IpBlocksConfiguration.from_dict(ip_blocks_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/NetworkConfiguration.md b/pnap_bmc_api/docs/NetworkConfiguration.md index c4786bcf..9e3c390f 100644 --- a/pnap_bmc_api/docs/NetworkConfiguration.md +++ b/pnap_bmc_api/docs/NetworkConfiguration.md @@ -21,12 +21,12 @@ json = "{}" # create an instance of NetworkConfiguration from a JSON string network_configuration_instance = NetworkConfiguration.from_json(json) # print the JSON string representation of the object -print NetworkConfiguration.to_json() +print(NetworkConfiguration.to_json()) # convert the object into a dict network_configuration_dict = network_configuration_instance.to_dict() # create an instance of NetworkConfiguration from a dict -network_configuration_form_dict = network_configuration.from_dict(network_configuration_dict) +network_configuration_from_dict = NetworkConfiguration.from_dict(network_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfiguration.md b/pnap_bmc_api/docs/OsConfiguration.md index 9ac96c02..11d2df52 100644 --- a/pnap_bmc_api/docs/OsConfiguration.md +++ b/pnap_bmc_api/docs/OsConfiguration.md @@ -26,12 +26,12 @@ json = "{}" # create an instance of OsConfiguration from a JSON string os_configuration_instance = OsConfiguration.from_json(json) # print the JSON string representation of the object -print OsConfiguration.to_json() +print(OsConfiguration.to_json()) # convert the object into a dict os_configuration_dict = os_configuration_instance.to_dict() # create an instance of OsConfiguration from a dict -os_configuration_form_dict = os_configuration.from_dict(os_configuration_dict) +os_configuration_from_dict = OsConfiguration.from_dict(os_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfigurationCloudInit.md b/pnap_bmc_api/docs/OsConfigurationCloudInit.md index 955fb39c..40eab56f 100644 --- a/pnap_bmc_api/docs/OsConfigurationCloudInit.md +++ b/pnap_bmc_api/docs/OsConfigurationCloudInit.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of OsConfigurationCloudInit from a JSON string os_configuration_cloud_init_instance = OsConfigurationCloudInit.from_json(json) # print the JSON string representation of the object -print OsConfigurationCloudInit.to_json() +print(OsConfigurationCloudInit.to_json()) # convert the object into a dict os_configuration_cloud_init_dict = os_configuration_cloud_init_instance.to_dict() # create an instance of OsConfigurationCloudInit from a dict -os_configuration_cloud_init_form_dict = os_configuration_cloud_init.from_dict(os_configuration_cloud_init_dict) +os_configuration_cloud_init_from_dict = OsConfigurationCloudInit.from_dict(os_configuration_cloud_init_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfigurationMap.md b/pnap_bmc_api/docs/OsConfigurationMap.md index 5b1492b1..7b8c5820 100644 --- a/pnap_bmc_api/docs/OsConfigurationMap.md +++ b/pnap_bmc_api/docs/OsConfigurationMap.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of OsConfigurationMap from a JSON string os_configuration_map_instance = OsConfigurationMap.from_json(json) # print the JSON string representation of the object -print OsConfigurationMap.to_json() +print(OsConfigurationMap.to_json()) # convert the object into a dict os_configuration_map_dict = os_configuration_map_instance.to_dict() # create an instance of OsConfigurationMap from a dict -os_configuration_map_form_dict = os_configuration_map.from_dict(os_configuration_map_dict) +os_configuration_map_from_dict = OsConfigurationMap.from_dict(os_configuration_map_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfigurationMapEsxi.md b/pnap_bmc_api/docs/OsConfigurationMapEsxi.md index f2abed9d..5428b4db 100644 --- a/pnap_bmc_api/docs/OsConfigurationMapEsxi.md +++ b/pnap_bmc_api/docs/OsConfigurationMapEsxi.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of OsConfigurationMapEsxi from a JSON string os_configuration_map_esxi_instance = OsConfigurationMapEsxi.from_json(json) # print the JSON string representation of the object -print OsConfigurationMapEsxi.to_json() +print(OsConfigurationMapEsxi.to_json()) # convert the object into a dict os_configuration_map_esxi_dict = os_configuration_map_esxi_instance.to_dict() # create an instance of OsConfigurationMapEsxi from a dict -os_configuration_map_esxi_form_dict = os_configuration_map_esxi.from_dict(os_configuration_map_esxi_dict) +os_configuration_map_esxi_from_dict = OsConfigurationMapEsxi.from_dict(os_configuration_map_esxi_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfigurationMapProxmox.md b/pnap_bmc_api/docs/OsConfigurationMapProxmox.md index c98705cd..9735e1df 100644 --- a/pnap_bmc_api/docs/OsConfigurationMapProxmox.md +++ b/pnap_bmc_api/docs/OsConfigurationMapProxmox.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of OsConfigurationMapProxmox from a JSON string os_configuration_map_proxmox_instance = OsConfigurationMapProxmox.from_json(json) # print the JSON string representation of the object -print OsConfigurationMapProxmox.to_json() +print(OsConfigurationMapProxmox.to_json()) # convert the object into a dict os_configuration_map_proxmox_dict = os_configuration_map_proxmox_instance.to_dict() # create an instance of OsConfigurationMapProxmox from a dict -os_configuration_map_proxmox_form_dict = os_configuration_map_proxmox.from_dict(os_configuration_map_proxmox_dict) +os_configuration_map_proxmox_from_dict = OsConfigurationMapProxmox.from_dict(os_configuration_map_proxmox_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfigurationNetrisController.md b/pnap_bmc_api/docs/OsConfigurationNetrisController.md index 7de53857..cd9916c1 100644 --- a/pnap_bmc_api/docs/OsConfigurationNetrisController.md +++ b/pnap_bmc_api/docs/OsConfigurationNetrisController.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of OsConfigurationNetrisController from a JSON string os_configuration_netris_controller_instance = OsConfigurationNetrisController.from_json(json) # print the JSON string representation of the object -print OsConfigurationNetrisController.to_json() +print(OsConfigurationNetrisController.to_json()) # convert the object into a dict os_configuration_netris_controller_dict = os_configuration_netris_controller_instance.to_dict() # create an instance of OsConfigurationNetrisController from a dict -os_configuration_netris_controller_form_dict = os_configuration_netris_controller.from_dict(os_configuration_netris_controller_dict) +os_configuration_netris_controller_from_dict = OsConfigurationNetrisController.from_dict(os_configuration_netris_controller_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfigurationNetrisSoftgate.md b/pnap_bmc_api/docs/OsConfigurationNetrisSoftgate.md index 536ad36c..4af78321 100644 --- a/pnap_bmc_api/docs/OsConfigurationNetrisSoftgate.md +++ b/pnap_bmc_api/docs/OsConfigurationNetrisSoftgate.md @@ -21,12 +21,12 @@ json = "{}" # create an instance of OsConfigurationNetrisSoftgate from a JSON string os_configuration_netris_softgate_instance = OsConfigurationNetrisSoftgate.from_json(json) # print the JSON string representation of the object -print OsConfigurationNetrisSoftgate.to_json() +print(OsConfigurationNetrisSoftgate.to_json()) # convert the object into a dict os_configuration_netris_softgate_dict = os_configuration_netris_softgate_instance.to_dict() # create an instance of OsConfigurationNetrisSoftgate from a dict -os_configuration_netris_softgate_form_dict = os_configuration_netris_softgate.from_dict(os_configuration_netris_softgate_dict) +os_configuration_netris_softgate_from_dict = OsConfigurationNetrisSoftgate.from_dict(os_configuration_netris_softgate_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/OsConfigurationWindows.md b/pnap_bmc_api/docs/OsConfigurationWindows.md index 7fba56dd..aecbfbb8 100644 --- a/pnap_bmc_api/docs/OsConfigurationWindows.md +++ b/pnap_bmc_api/docs/OsConfigurationWindows.md @@ -7,6 +7,7 @@ Windows OS configuration properties. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **rdp_allowed_ips** | **List[str]** | List of IPs allowed for RDP access to Windows OS. Supported in single IP, CIDR and range format. When undefined, RDP is disabled. To allow RDP access from any IP use 0.0.0.0/0. This will only be returned in response to provisioning a server. | [optional] +**bring_your_own_license** | **bool** | Use a Bring Your Own (BYO) Windows license. If true, the server is provisioned in trial mode, and you must activate your own license. If false (default), the server includes a managed Windows license billed by the platform. | [optional] [default to False] ## Example @@ -18,12 +19,12 @@ json = "{}" # create an instance of OsConfigurationWindows from a JSON string os_configuration_windows_instance = OsConfigurationWindows.from_json(json) # print the JSON string representation of the object -print OsConfigurationWindows.to_json() +print(OsConfigurationWindows.to_json()) # convert the object into a dict os_configuration_windows_dict = os_configuration_windows_instance.to_dict() # create an instance of OsConfigurationWindows from a dict -os_configuration_windows_form_dict = os_configuration_windows.from_dict(os_configuration_windows_dict) +os_configuration_windows_from_dict = OsConfigurationWindows.from_dict(os_configuration_windows_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/PrivateNetworkConfiguration.md b/pnap_bmc_api/docs/PrivateNetworkConfiguration.md index 63a7e887..43bd8211 100644 --- a/pnap_bmc_api/docs/PrivateNetworkConfiguration.md +++ b/pnap_bmc_api/docs/PrivateNetworkConfiguration.md @@ -8,7 +8,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **gateway_address** | **str** | Deprecated in favour of a common gateway address across all networks available under NetworkConfiguration.<br> The address of the gateway assigned / to assign to the server.<br> When used as part of request body, IP address has to be part of private network assigned to this server.<br> Gateway address also has to be assigned on an already deployed resource unless the `force` query parameter is true. | [optional] **configuration_type** | **str** | (Write-only) Determines the approach for configuring private network(s) for the server being provisioned. Currently this field should be set to `USE_OR_CREATE_DEFAULT`, `USER_DEFINED` or `NONE`. | [optional] [default to 'USE_OR_CREATE_DEFAULT'] -**private_networks** | [**List[ServerPrivateNetwork]**](ServerPrivateNetwork.md) | The list of private networks this server is member of. When this field is part of request body, it'll be used to specify the private networks to assign to this server upon provisioning. Used alongside the `USER_DEFINED` configurationType. | [optional] +**private_networks** | [**List[ServerPrivateNetwork]**](ServerPrivateNetwork.md) | The list of private networks this server belongs to. If this field is part of a request body, it will be used for specifying the private networks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType. | [optional] ## Example @@ -20,12 +20,12 @@ json = "{}" # create an instance of PrivateNetworkConfiguration from a JSON string private_network_configuration_instance = PrivateNetworkConfiguration.from_json(json) # print the JSON string representation of the object -print PrivateNetworkConfiguration.to_json() +print(PrivateNetworkConfiguration.to_json()) # convert the object into a dict private_network_configuration_dict = private_network_configuration_instance.to_dict() # create an instance of PrivateNetworkConfiguration from a dict -private_network_configuration_form_dict = private_network_configuration.from_dict(private_network_configuration_dict) +private_network_configuration_from_dict = PrivateNetworkConfiguration.from_dict(private_network_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/PublicNetworkConfiguration.md b/pnap_bmc_api/docs/PublicNetworkConfiguration.md index de2ff64b..54391577 100644 --- a/pnap_bmc_api/docs/PublicNetworkConfiguration.md +++ b/pnap_bmc_api/docs/PublicNetworkConfiguration.md @@ -6,7 +6,7 @@ Public network details of bare metal server. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**public_networks** | [**List[ServerPublicNetwork]**](ServerPublicNetwork.md) | The list of public networks this server is member of. When this field is part of request body, it'll be used to specify the public networks to assign to this server upon provisioning. | [optional] +**public_networks** | [**List[ServerPublicNetwork]**](ServerPublicNetwork.md) | The list of public networks this server belongs to. If this field is part of a request body, it will be used for specifying the public networks to assign to this server on provision. Only IPv4 addresses can be specified. | [optional] ## Example @@ -18,12 +18,12 @@ json = "{}" # create an instance of PublicNetworkConfiguration from a JSON string public_network_configuration_instance = PublicNetworkConfiguration.from_json(json) # print the JSON string representation of the object -print PublicNetworkConfiguration.to_json() +print(PublicNetworkConfiguration.to_json()) # convert the object into a dict public_network_configuration_dict = public_network_configuration_instance.to_dict() # create an instance of PublicNetworkConfiguration from a dict -public_network_configuration_form_dict = public_network_configuration.from_dict(public_network_configuration_dict) +public_network_configuration_from_dict = PublicNetworkConfiguration.from_dict(public_network_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/Quota.md b/pnap_bmc_api/docs/Quota.md index 7def8e3e..014b2d3d 100644 --- a/pnap_bmc_api/docs/Quota.md +++ b/pnap_bmc_api/docs/Quota.md @@ -25,12 +25,12 @@ json = "{}" # create an instance of Quota from a JSON string quota_instance = Quota.from_json(json) # print the JSON string representation of the object -print Quota.to_json() +print(Quota.to_json()) # convert the object into a dict quota_dict = quota_instance.to_dict() # create an instance of Quota from a dict -quota_form_dict = quota.from_dict(quota_dict) +quota_from_dict = Quota.from_dict(quota_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/QuotaEditLimitRequest.md b/pnap_bmc_api/docs/QuotaEditLimitRequest.md index bfd59032..9de1abcf 100644 --- a/pnap_bmc_api/docs/QuotaEditLimitRequest.md +++ b/pnap_bmc_api/docs/QuotaEditLimitRequest.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of QuotaEditLimitRequest from a JSON string quota_edit_limit_request_instance = QuotaEditLimitRequest.from_json(json) # print the JSON string representation of the object -print QuotaEditLimitRequest.to_json() +print(QuotaEditLimitRequest.to_json()) # convert the object into a dict quota_edit_limit_request_dict = quota_edit_limit_request_instance.to_dict() # create an instance of QuotaEditLimitRequest from a dict -quota_edit_limit_request_form_dict = quota_edit_limit_request.from_dict(quota_edit_limit_request_dict) +quota_edit_limit_request_from_dict = QuotaEditLimitRequest.from_dict(quota_edit_limit_request_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/QuotaEditLimitRequestDetails.md b/pnap_bmc_api/docs/QuotaEditLimitRequestDetails.md index b029cfe6..ff919faf 100644 --- a/pnap_bmc_api/docs/QuotaEditLimitRequestDetails.md +++ b/pnap_bmc_api/docs/QuotaEditLimitRequestDetails.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of QuotaEditLimitRequestDetails from a JSON string quota_edit_limit_request_details_instance = QuotaEditLimitRequestDetails.from_json(json) # print the JSON string representation of the object -print QuotaEditLimitRequestDetails.to_json() +print(QuotaEditLimitRequestDetails.to_json()) # convert the object into a dict quota_edit_limit_request_details_dict = quota_edit_limit_request_details_instance.to_dict() # create an instance of QuotaEditLimitRequestDetails from a dict -quota_edit_limit_request_details_form_dict = quota_edit_limit_request_details.from_dict(quota_edit_limit_request_details_dict) +quota_edit_limit_request_details_from_dict = QuotaEditLimitRequestDetails.from_dict(quota_edit_limit_request_details_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/QuotasApi.md b/pnap_bmc_api/docs/QuotasApi.md index 302f697e..46438264 100644 --- a/pnap_bmc_api/docs/QuotasApi.md +++ b/pnap_bmc_api/docs/QuotasApi.md @@ -21,8 +21,6 @@ Get account quota details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.quota import Quota from pnap_bmc_api.rest import ApiException @@ -98,8 +96,6 @@ Sends a request to edit the limit of a quota. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.quota_edit_limit_request import QuotaEditLimitRequest from pnap_bmc_api.rest import ApiException @@ -179,8 +175,6 @@ Get account quota details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.quota import Quota from pnap_bmc_api.rest import ApiException diff --git a/pnap_bmc_api/docs/RelinquishIpBlock.md b/pnap_bmc_api/docs/RelinquishIpBlock.md index 42cbbf6c..7f639699 100644 --- a/pnap_bmc_api/docs/RelinquishIpBlock.md +++ b/pnap_bmc_api/docs/RelinquishIpBlock.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of RelinquishIpBlock from a JSON string relinquish_ip_block_instance = RelinquishIpBlock.from_json(json) # print the JSON string representation of the object -print RelinquishIpBlock.to_json() +print(RelinquishIpBlock.to_json()) # convert the object into a dict relinquish_ip_block_dict = relinquish_ip_block_instance.to_dict() # create an instance of RelinquishIpBlock from a dict -relinquish_ip_block_form_dict = relinquish_ip_block.from_dict(relinquish_ip_block_dict) +relinquish_ip_block_from_dict = RelinquishIpBlock.from_dict(relinquish_ip_block_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ReservationTransferDetails.md b/pnap_bmc_api/docs/ReservationTransferDetails.md new file mode 100644 index 00000000..39e72e0e --- /dev/null +++ b/pnap_bmc_api/docs/ReservationTransferDetails.md @@ -0,0 +1,30 @@ +# ReservationTransferDetails + +Reservation transfer details. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**target_server_id** | **str** | ID of target server to transfer reservation to. | + +## Example + +```python +from pnap_bmc_api.models.reservation_transfer_details import ReservationTransferDetails + +# TODO update the JSON string below +json = "{}" +# create an instance of ReservationTransferDetails from a JSON string +reservation_transfer_details_instance = ReservationTransferDetails.from_json(json) +# print the JSON string representation of the object +print(ReservationTransferDetails.to_json()) + +# convert the object into a dict +reservation_transfer_details_dict = reservation_transfer_details_instance.to_dict() +# create an instance of ReservationTransferDetails from a dict +reservation_transfer_details_from_dict = ReservationTransferDetails.from_dict(reservation_transfer_details_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pnap_bmc_api/docs/ResetResult.md b/pnap_bmc_api/docs/ResetResult.md index 8a889b3c..4f2fccd6 100644 --- a/pnap_bmc_api/docs/ResetResult.md +++ b/pnap_bmc_api/docs/ResetResult.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of ResetResult from a JSON string reset_result_instance = ResetResult.from_json(json) # print the JSON string representation of the object -print ResetResult.to_json() +print(ResetResult.to_json()) # convert the object into a dict reset_result_dict = reset_result_instance.to_dict() # create an instance of ResetResult from a dict -reset_result_form_dict = reset_result.from_dict(reset_result_dict) +reset_result_from_dict = ResetResult.from_dict(reset_result_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/SSHKeysApi.md b/pnap_bmc_api/docs/SSHKeysApi.md index 405b4ae5..01bfbcb8 100644 --- a/pnap_bmc_api/docs/SSHKeysApi.md +++ b/pnap_bmc_api/docs/SSHKeysApi.md @@ -23,8 +23,6 @@ List all SSH Keys. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.ssh_key import SshKey from pnap_bmc_api.rest import ApiException @@ -99,8 +97,6 @@ Create an SSH Key. SSH Keys created can be used for server creation and reset fu * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.ssh_key import SshKey from pnap_bmc_api.models.ssh_key_create import SshKeyCreate @@ -182,8 +178,6 @@ Delete an SSH Key. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.delete_ssh_key_result import DeleteSshKeyResult from pnap_bmc_api.rest import ApiException @@ -263,8 +257,6 @@ Get SSH Key details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.ssh_key import SshKey from pnap_bmc_api.rest import ApiException @@ -344,8 +336,6 @@ Edit SSH Key details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.ssh_key import SshKey from pnap_bmc_api.models.ssh_key_update import SshKeyUpdate diff --git a/pnap_bmc_api/docs/Server.md b/pnap_bmc_api/docs/Server.md index b4c94914..88cb1df3 100644 --- a/pnap_bmc_api/docs/Server.md +++ b/pnap_bmc_api/docs/Server.md @@ -10,9 +10,9 @@ Name | Type | Description | Notes **status** | **str** | The status of the server. Can have one of the following values: `creating` , `powered-on` , `powered-off` , `rebooting` , `resetting` , `deleting` , `reserved` , `error` or `reinstating`. | **hostname** | **str** | Hostname of server. | **description** | **str** | Description of server. | [optional] -**os** | **str** | The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. | [optional] -**type** | **str** | Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, s4.x6.c6.large or s4.x6.m6.xlarge. | -**location** | **str** | Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. | +**os** | **str** | The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. | [optional] +**type** | **str** | Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, `d3.g3.c2.medium`, `s4.x6.c6.large`, `s4.x6.m6.xlarge`, `s5.x6.c3.medium`, `s5.x6.c3.large`, `s5.x6.c8.medium`, `s5.x6.c9.medium`, `s5.x6.c8.large`, `s5.x6.c9.large`, `s5.x6.m8.xlarge`, `s5.x6.m9.xlarge`, `s4.c3.medium`, `s4.c6.medium`, `s4.c6.large`, `s4.c6.xlarge`, `s4.s2.large`, `a2.c9.large` or `a2.c9.xlarge`. | +**location** | **str** | Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. | **cpu** | **str** | A description of the machine CPU. | **cpu_count** | **int** | The number of CPUs available in the system. | **cores_per_cpu** | **int** | The number of physical cores present on each CPU. | @@ -45,12 +45,12 @@ json = "{}" # create an instance of Server from a JSON string server_instance = Server.from_json(json) # print the JSON string representation of the object -print Server.to_json() +print(Server.to_json()) # convert the object into a dict server_dict = server_instance.to_dict() # create an instance of Server from a dict -server_form_dict = server.from_dict(server_dict) +server_from_dict = Server.from_dict(server_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerCreate.md b/pnap_bmc_api/docs/ServerCreate.md index 03e62858..98bcb7b3 100644 --- a/pnap_bmc_api/docs/ServerCreate.md +++ b/pnap_bmc_api/docs/ServerCreate.md @@ -8,9 +8,9 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **hostname** | **str** | Hostname of server. | **description** | **str** | Description of server. | [optional] -**os** | **str** | The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. | -**type** | **str** | Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, s4.x6.c6.large or s4.x6.m6.xlarge. | -**location** | **str** | Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. | +**os** | **str** | The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. | +**type** | **str** | Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`,`d3.g3.c2.medium`, `s4.x6.c6.large`, `s4.x6.m6.xlarge`, `s5.x6.c3.medium`, `s5.x6.c3.large`, `s5.x6.c8.medium`, `s5.x6.c9.medium`, `s5.x6.c8.large`, `s5.x6.c9.large`, `s5.x6.m8.xlarge`, `s5.x6.m9.xlarge`, `s4.c3.medium`, `s4.c6.medium`, `s4.c6.large`, `s4.c6.xlarge`, `s4.s2.large`, `a2.c9.large` or `a2.c9.xlarge`. | +**location** | **str** | Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. | **install_default_ssh_keys** | **bool** | Whether or not to install SSH keys marked as default in addition to any SSH keys specified in this request. | [optional] [default to True] **ssh_keys** | **List[str]** | A list of SSH keys that will be installed on the server. | [optional] **ssh_key_ids** | **List[str]** | A list of SSH key IDs that will be installed on the server in addition to any SSH keys specified in this request. | [optional] @@ -32,12 +32,12 @@ json = "{}" # create an instance of ServerCreate from a JSON string server_create_instance = ServerCreate.from_json(json) # print the JSON string representation of the object -print ServerCreate.to_json() +print(ServerCreate.to_json()) # convert the object into a dict server_create_dict = server_create_instance.to_dict() # create an instance of ServerCreate from a dict -server_create_form_dict = server_create.from_dict(server_create_dict) +server_create_from_dict = ServerCreate.from_dict(server_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerIpBlock.md b/pnap_bmc_api/docs/ServerIpBlock.md index 90af13ad..d0ce51fd 100644 --- a/pnap_bmc_api/docs/ServerIpBlock.md +++ b/pnap_bmc_api/docs/ServerIpBlock.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of ServerIpBlock from a JSON string server_ip_block_instance = ServerIpBlock.from_json(json) # print the JSON string representation of the object -print ServerIpBlock.to_json() +print(ServerIpBlock.to_json()) # convert the object into a dict server_ip_block_dict = server_ip_block_instance.to_dict() # create an instance of ServerIpBlock from a dict -server_ip_block_form_dict = server_ip_block.from_dict(server_ip_block_dict) +server_ip_block_from_dict = ServerIpBlock.from_dict(server_ip_block_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerNetworkUpdate.md b/pnap_bmc_api/docs/ServerNetworkUpdate.md index 174f7ab7..e756e1f4 100644 --- a/pnap_bmc_api/docs/ServerNetworkUpdate.md +++ b/pnap_bmc_api/docs/ServerNetworkUpdate.md @@ -6,7 +6,7 @@ Update network details of bare metal server. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**ips** | **List[str]** | List of IPs to be associated to the server.<br> Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). IPs must be within the network's range.<br> Setting the `force` query parameter to `true` allows you to:<ul> <li> Assign no specific IP addresses by designating an empty array of IPs. <li> Assign one or more IP addresses which are already configured on other resource(s) in network. <li> Assign IP addresses which are considered as reserved in network.</ul> | [optional] +**ips** | **List[str]** | List of IPs to be associated to the server.<br> Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). All IPs must be within the network's range.<br> Setting the `force` query parameter to `true` allows you to:<ul> <li> Assign no specific IP addresses by designating an empty array of IPs. <li> Assign one or more IP addresses which are already configured on other resource(s) in network. <li> Assign IP addresses which are considered as reserved in network.</ul> | [optional] ## Example @@ -18,12 +18,12 @@ json = "{}" # create an instance of ServerNetworkUpdate from a JSON string server_network_update_instance = ServerNetworkUpdate.from_json(json) # print the JSON string representation of the object -print ServerNetworkUpdate.to_json() +print(ServerNetworkUpdate.to_json()) # convert the object into a dict server_network_update_dict = server_network_update_instance.to_dict() # create an instance of ServerNetworkUpdate from a dict -server_network_update_form_dict = server_network_update.from_dict(server_network_update_dict) +server_network_update_from_dict = ServerNetworkUpdate.from_dict(server_network_update_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerPatch.md b/pnap_bmc_api/docs/ServerPatch.md index cfe86bf8..ffcfc7f9 100644 --- a/pnap_bmc_api/docs/ServerPatch.md +++ b/pnap_bmc_api/docs/ServerPatch.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of ServerPatch from a JSON string server_patch_instance = ServerPatch.from_json(json) # print the JSON string representation of the object -print ServerPatch.to_json() +print(ServerPatch.to_json()) # convert the object into a dict server_patch_dict = server_patch_instance.to_dict() # create an instance of ServerPatch from a dict -server_patch_form_dict = server_patch.from_dict(server_patch_dict) +server_patch_from_dict = ServerPatch.from_dict(server_patch_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerPrivateNetwork.md b/pnap_bmc_api/docs/ServerPrivateNetwork.md index ea1903ae..a8fa2330 100644 --- a/pnap_bmc_api/docs/ServerPrivateNetwork.md +++ b/pnap_bmc_api/docs/ServerPrivateNetwork.md @@ -8,8 +8,9 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **str** | The network identifier. | **ips** | **List[str]** | IPs to configure/configured on the server.<br> Valid IP formats are single IPv4 addresses or IPv4 ranges. IPs must be within the network's range. Should be null or empty list if DHCP is true. <br> If field is undefined and DHCP is false, next available IP in network will be automatically allocated.<br> If the network contains a membership of type 'storage', the first twelve IPs are already reserved by BMC and not usable.<br> Setting the `force` query parameter to `true` allows you to:<ul> <li> Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network. <li> Assign one or more IP addresses which are already configured on other resource(s) in network. <li> Assign IP addresses which are considered as reserved in network.</ul> | [optional] -**dhcp** | **bool** | Determines whether DHCP is enabled for this server. Should be false if any IPs are provided. Not supported for Proxmox OS. | [optional] [default to False] +**dhcp** | **bool** | Determines whether DHCP is enabled for this server.<br> The following restrictions apply when enabling DHCP:<ul> <li> DHCP support is limited to servers configured exclusively with private networks (PRIVATE_ONLY). <li> DHCP value needs to be consistent across all server-configured private networks. <li> The server does not support manual gateway address configuration. <li> Private IP addresses for network cannot be specified.</ul> Note: Not supported on Proxmox OS. | [optional] [default to False] **status_description** | **str** | (Read-only) The status of the network. | [optional] [readonly] +**vlan_id** | **int** | (Read-only) The VLAN on which this network has been configured within the network switch. | [optional] [readonly] ## Example @@ -21,12 +22,12 @@ json = "{}" # create an instance of ServerPrivateNetwork from a JSON string server_private_network_instance = ServerPrivateNetwork.from_json(json) # print the JSON string representation of the object -print ServerPrivateNetwork.to_json() +print(ServerPrivateNetwork.to_json()) # convert the object into a dict server_private_network_dict = server_private_network_instance.to_dict() # create an instance of ServerPrivateNetwork from a dict -server_private_network_form_dict = server_private_network.from_dict(server_private_network_dict) +server_private_network_from_dict = ServerPrivateNetwork.from_dict(server_private_network_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerProvision.md b/pnap_bmc_api/docs/ServerProvision.md index 80b35526..4edd48a2 100644 --- a/pnap_bmc_api/docs/ServerProvision.md +++ b/pnap_bmc_api/docs/ServerProvision.md @@ -8,7 +8,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **hostname** | **str** | Hostname of server. | **description** | **str** | Description of server. | [optional] -**os** | **str** | The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux8`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. | +**os** | **str** | The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux8`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`,`netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. | **install_default_ssh_keys** | **bool** | Whether or not to install SSH keys marked as default in addition to any SSH keys specified in this request. | [optional] [default to True] **ssh_keys** | **List[str]** | A list of SSH keys that will be installed on the server. | [optional] **ssh_key_ids** | **List[str]** | A list of SSH key IDs that will be installed on the server in addition to any SSH keys specified in this request. | [optional] @@ -28,12 +28,12 @@ json = "{}" # create an instance of ServerProvision from a JSON string server_provision_instance = ServerProvision.from_json(json) # print the JSON string representation of the object -print ServerProvision.to_json() +print(ServerProvision.to_json()) # convert the object into a dict server_provision_dict = server_provision_instance.to_dict() # create an instance of ServerProvision from a dict -server_provision_form_dict = server_provision.from_dict(server_provision_dict) +server_provision_from_dict = ServerProvision.from_dict(server_provision_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerPublicNetwork.md b/pnap_bmc_api/docs/ServerPublicNetwork.md index aeeb3900..b4fa341e 100644 --- a/pnap_bmc_api/docs/ServerPublicNetwork.md +++ b/pnap_bmc_api/docs/ServerPublicNetwork.md @@ -7,9 +7,10 @@ Public network details of bare metal server. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **str** | The network identifier. | -**ips** | **List[str]** | Configurable/configured IPs on the server.<br> At least 1 IP address is required. Valid IP format is single IP addresses. All IPs must be within the network's range.<br> Setting the `computeSlaacIp` field to `true` allows you to provide an empty array of IPs.<br> Additionally, setting the `force` query parameter to `true` allows you to:<ul> <li> Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network. <li> Assign one or more IP addresses which are already configured on other resource(s) in network.</ul> | [optional] +**ips** | **List[str]** | Configurable/configured IPs on the server.<br> At least 1 IP address is required. Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). All IPs must be within the network's range.<br> Setting the `computeSlaacIp` field to `true` allows you to provide an empty array of IPs.<br> Additionally, setting the `force` query parameter to `true` allows you to:<ul> <li> Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network. <li> Assign one or more IP addresses which are already configured on other resource(s) in network.</ul> | [optional] **status_description** | **str** | (Read-only) The status of the assignment to the network. | [optional] [readonly] **compute_slaac_ip** | **bool** | (Write-only) Requests Stateless Address Autoconfiguration (SLAAC). Applicable for Network which contains IPv6 block(s). | [optional] +**vlan_id** | **int** | (Read-only) The VLAN on which this network has been configured within the network switch. | [optional] [readonly] ## Example @@ -21,12 +22,12 @@ json = "{}" # create an instance of ServerPublicNetwork from a JSON string server_public_network_instance = ServerPublicNetwork.from_json(json) # print the JSON string representation of the object -print ServerPublicNetwork.to_json() +print(ServerPublicNetwork.to_json()) # convert the object into a dict server_public_network_dict = server_public_network_instance.to_dict() # create an instance of ServerPublicNetwork from a dict -server_public_network_form_dict = server_public_network.from_dict(server_public_network_dict) +server_public_network_from_dict = ServerPublicNetwork.from_dict(server_public_network_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerReserve.md b/pnap_bmc_api/docs/ServerReserve.md index 1da1b177..76bbc415 100644 --- a/pnap_bmc_api/docs/ServerReserve.md +++ b/pnap_bmc_api/docs/ServerReserve.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of ServerReserve from a JSON string server_reserve_instance = ServerReserve.from_json(json) # print the JSON string representation of the object -print ServerReserve.to_json() +print(ServerReserve.to_json()) # convert the object into a dict server_reserve_dict = server_reserve_instance.to_dict() # create an instance of ServerReserve from a dict -server_reserve_form_dict = server_reserve.from_dict(server_reserve_dict) +server_reserve_from_dict = ServerReserve.from_dict(server_reserve_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServerReset.md b/pnap_bmc_api/docs/ServerReset.md index 5706365a..f6c6847f 100644 --- a/pnap_bmc_api/docs/ServerReset.md +++ b/pnap_bmc_api/docs/ServerReset.md @@ -21,12 +21,12 @@ json = "{}" # create an instance of ServerReset from a JSON string server_reset_instance = ServerReset.from_json(json) # print the JSON string representation of the object -print ServerReset.to_json() +print(ServerReset.to_json()) # convert the object into a dict server_reset_dict = server_reset_instance.to_dict() # create an instance of ServerReset from a dict -server_reset_form_dict = server_reset.from_dict(server_reset_dict) +server_reset_from_dict = ServerReset.from_dict(server_reset_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/ServersApi.md b/pnap_bmc_api/docs/ServersApi.md index 54185670..1eb13839 100644 --- a/pnap_bmc_api/docs/ServersApi.md +++ b/pnap_bmc_api/docs/ServersApi.md @@ -15,6 +15,7 @@ Method | HTTP request | Description [**servers_server_id_actions_reserve_post**](ServersApi.md#servers_server_id_actions_reserve_post) | **POST** /servers/{serverId}/actions/reserve | Reserve server. [**servers_server_id_actions_reset_post**](ServersApi.md#servers_server_id_actions_reset_post) | **POST** /servers/{serverId}/actions/reset | Reset server. [**servers_server_id_actions_shutdown_post**](ServersApi.md#servers_server_id_actions_shutdown_post) | **POST** /servers/{serverId}/actions/shutdown | Shutdown server. +[**servers_server_id_actions_transfer_reservation**](ServersApi.md#servers_server_id_actions_transfer_reservation) | **POST** /servers/{serverId}/actions/transfer-reservation | Transfer server reservation. [**servers_server_id_delete**](ServersApi.md#servers_server_id_delete) | **DELETE** /servers/{serverId} | Delete server. [**servers_server_id_get**](ServersApi.md#servers_server_id_get) | **GET** /servers/{serverId} | Get server. [**servers_server_id_ip_blocks_ip_block_id_delete**](ServersApi.md#servers_server_id_ip_blocks_ip_block_id_delete) | **DELETE** /servers/{serverId}/network-configuration/ip-block-configurations/ip-blocks/{ipBlockId} | Unassign IP Block from Server. @@ -40,8 +41,6 @@ Removes the server from private network. No actual configuration is performed * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.rest import ApiException from pprint import pprint @@ -123,8 +122,6 @@ List all servers owned by account. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server import Server from pnap_bmc_api.rest import ApiException @@ -203,8 +200,6 @@ Create (request) a new server for the account. Server DNS will be configured to * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server import Server from pnap_bmc_api.models.server_create import ServerCreate @@ -289,8 +284,6 @@ Deprovision the server. Supports advanced deprovision configuration. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.relinquish_ip_block import RelinquishIpBlock from pnap_bmc_api.rest import ApiException @@ -373,8 +366,6 @@ Power off specific server. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.action_result import ActionResult from pnap_bmc_api.rest import ApiException @@ -455,8 +446,6 @@ Power on specific server. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.action_result import ActionResult from pnap_bmc_api.rest import ApiException @@ -537,8 +526,6 @@ Provision reserved server. Server DNS will be configured to access Google's publ * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server import Server from pnap_bmc_api.models.server_provision import ServerProvision @@ -625,8 +612,6 @@ Reboot specific server. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.action_result import ActionResult from pnap_bmc_api.rest import ApiException @@ -707,8 +692,6 @@ Reserve specific server. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server import Server from pnap_bmc_api.models.server_reserve import ServerReserve @@ -792,8 +775,6 @@ Deprecated: Reset specific server. Reset only supports network configurations of * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.reset_result import ResetResult from pnap_bmc_api.models.server_reset import ServerReset @@ -877,8 +858,6 @@ Shut down specific server. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.action_result import ActionResult from pnap_bmc_api.rest import ApiException @@ -947,6 +926,89 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **servers_server_id_actions_transfer_reservation** +> Server servers_server_id_actions_transfer_reservation(server_id, reservation_transfer_details) + +Transfer server reservation. + +Transfer server reservation. An active (READY) reservation can be transferred from a server in ERROR or RESERVED status to another HOURLY provisioned server of the same location and type. + +### Example + +* OAuth Authentication (OAuth2): + +```python +import pnap_bmc_api +from pnap_bmc_api.models.reservation_transfer_details import ReservationTransferDetails +from pnap_bmc_api.models.server import Server +from pnap_bmc_api.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://api.phoenixnap.com/bmc/v1 +# See configuration.py for a list of all supported configuration parameters. +configuration = pnap_bmc_api.Configuration( + host = "https://api.phoenixnap.com/bmc/v1" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +configuration.access_token = os.environ["ACCESS_TOKEN"] + +# Enter a context with an instance of the API client +with pnap_bmc_api.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = pnap_bmc_api.ServersApi(api_client) + server_id = '60473a6115e34466c9f8f083' # str | The server's ID. + reservation_transfer_details = {"targetServerId":"54a21648dasda4s9843a17"} # ReservationTransferDetails | + + try: + # Transfer server reservation. + api_response = api_instance.servers_server_id_actions_transfer_reservation(server_id, reservation_transfer_details) + print("The response of ServersApi->servers_server_id_actions_transfer_reservation:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling ServersApi->servers_server_id_actions_transfer_reservation: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **server_id** | **str**| The server's ID. | + **reservation_transfer_details** | [**ReservationTransferDetails**](ReservationTransferDetails.md)| | + +### Return type + +[**Server**](Server.md) + +### Authorization + +[OAuth2](../README.md#OAuth2) + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | The server reservation has been successfully transferred. | - | +**400** | The request failed due to wrong data. Please check the provided parameters and try again. | - | +**401** | The request failed due to invalid credentials. Please check the provided credentials and try again. | - | +**403** | The request failed since this resource cannot be accessed by the provided credentials. | - | +**409** | The resource is in an incompatible state. | - | +**500** | The server encountered an unexpected condition that prevented it from fulfilling the request. | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **servers_server_id_delete** > DeleteResult servers_server_id_delete(server_id) @@ -959,8 +1021,6 @@ Deprovision specific server. Any IP blocks assigned to this server will also be * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.delete_result import DeleteResult from pnap_bmc_api.rest import ApiException @@ -1040,8 +1100,6 @@ Get server properties. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server import Server from pnap_bmc_api.rest import ApiException @@ -1121,8 +1179,6 @@ Removes the IP block from the server. No actual configuration is performed on * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.relinquish_ip_block import RelinquishIpBlock from pnap_bmc_api.rest import ApiException @@ -1207,8 +1263,6 @@ Adds an IP block to this server. No actual configuration is performed on the * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server_ip_block import ServerIpBlock from pnap_bmc_api.rest import ApiException @@ -1291,8 +1345,6 @@ Any changes to the hostname or description using the BMC API will reflect solely * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server import Server from pnap_bmc_api.models.server_patch import ServerPatch @@ -1375,8 +1427,6 @@ IP address changes intended to keep the BMC data up to date with server's operat * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server_network_update import ServerNetworkUpdate from pnap_bmc_api.models.server_private_network import ServerPrivateNetwork @@ -1464,8 +1514,6 @@ Adds the server to a private network. No actual configuration is performed on * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server_private_network import ServerPrivateNetwork from pnap_bmc_api.rest import ApiException @@ -1549,8 +1597,6 @@ Removes the server from the Public Network. No actual configuration is perfor * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.rest import ApiException from pprint import pprint @@ -1632,8 +1678,6 @@ IP address changes intended to keep the BMC data up to date with server's operat * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server_network_update import ServerNetworkUpdate from pnap_bmc_api.models.server_public_network import ServerPublicNetwork @@ -1721,8 +1765,6 @@ Adds the server to a Public Network. No actual configuration is performed on * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server_public_network import ServerPublicNetwork from pnap_bmc_api.rest import ApiException @@ -1807,8 +1849,6 @@ Overwrites tags assigned for Server and unassigns any tags not part of the reque * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_bmc_api from pnap_bmc_api.models.server import Server from pnap_bmc_api.models.tag_assignment_request import TagAssignmentRequest diff --git a/pnap_bmc_api/docs/SshKey.md b/pnap_bmc_api/docs/SshKey.md index 27cc280a..4b02e5f2 100644 --- a/pnap_bmc_api/docs/SshKey.md +++ b/pnap_bmc_api/docs/SshKey.md @@ -24,12 +24,12 @@ json = "{}" # create an instance of SshKey from a JSON string ssh_key_instance = SshKey.from_json(json) # print the JSON string representation of the object -print SshKey.to_json() +print(SshKey.to_json()) # convert the object into a dict ssh_key_dict = ssh_key_instance.to_dict() # create an instance of SshKey from a dict -ssh_key_form_dict = ssh_key.from_dict(ssh_key_dict) +ssh_key_from_dict = SshKey.from_dict(ssh_key_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/SshKeyCreate.md b/pnap_bmc_api/docs/SshKeyCreate.md index 51f0a10d..f1a95124 100644 --- a/pnap_bmc_api/docs/SshKeyCreate.md +++ b/pnap_bmc_api/docs/SshKeyCreate.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of SshKeyCreate from a JSON string ssh_key_create_instance = SshKeyCreate.from_json(json) # print the JSON string representation of the object -print SshKeyCreate.to_json() +print(SshKeyCreate.to_json()) # convert the object into a dict ssh_key_create_dict = ssh_key_create_instance.to_dict() # create an instance of SshKeyCreate from a dict -ssh_key_create_form_dict = ssh_key_create.from_dict(ssh_key_create_dict) +ssh_key_create_from_dict = SshKeyCreate.from_dict(ssh_key_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/SshKeyUpdate.md b/pnap_bmc_api/docs/SshKeyUpdate.md index 7ee15a3c..e4ada724 100644 --- a/pnap_bmc_api/docs/SshKeyUpdate.md +++ b/pnap_bmc_api/docs/SshKeyUpdate.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of SshKeyUpdate from a JSON string ssh_key_update_instance = SshKeyUpdate.from_json(json) # print the JSON string representation of the object -print SshKeyUpdate.to_json() +print(SshKeyUpdate.to_json()) # convert the object into a dict ssh_key_update_dict = ssh_key_update_instance.to_dict() # create an instance of SshKeyUpdate from a dict -ssh_key_update_form_dict = ssh_key_update.from_dict(ssh_key_update_dict) +ssh_key_update_from_dict = SshKeyUpdate.from_dict(ssh_key_update_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/StorageConfiguration.md b/pnap_bmc_api/docs/StorageConfiguration.md index e3b4094a..f96f70ea 100644 --- a/pnap_bmc_api/docs/StorageConfiguration.md +++ b/pnap_bmc_api/docs/StorageConfiguration.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of StorageConfiguration from a JSON string storage_configuration_instance = StorageConfiguration.from_json(json) # print the JSON string representation of the object -print StorageConfiguration.to_json() +print(StorageConfiguration.to_json()) # convert the object into a dict storage_configuration_dict = storage_configuration_instance.to_dict() # create an instance of StorageConfiguration from a dict -storage_configuration_form_dict = storage_configuration.from_dict(storage_configuration_dict) +storage_configuration_from_dict = StorageConfiguration.from_dict(storage_configuration_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/StorageConfigurationRootPartition.md b/pnap_bmc_api/docs/StorageConfigurationRootPartition.md index 3009f260..b29fd5a6 100644 --- a/pnap_bmc_api/docs/StorageConfigurationRootPartition.md +++ b/pnap_bmc_api/docs/StorageConfigurationRootPartition.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of StorageConfigurationRootPartition from a JSON string storage_configuration_root_partition_instance = StorageConfigurationRootPartition.from_json(json) # print the JSON string representation of the object -print StorageConfigurationRootPartition.to_json() +print(StorageConfigurationRootPartition.to_json()) # convert the object into a dict storage_configuration_root_partition_dict = storage_configuration_root_partition_instance.to_dict() # create an instance of StorageConfigurationRootPartition from a dict -storage_configuration_root_partition_form_dict = storage_configuration_root_partition.from_dict(storage_configuration_root_partition_dict) +storage_configuration_root_partition_from_dict = StorageConfigurationRootPartition.from_dict(storage_configuration_root_partition_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/TagAssignment.md b/pnap_bmc_api/docs/TagAssignment.md index 7443caa8..1236e48b 100644 --- a/pnap_bmc_api/docs/TagAssignment.md +++ b/pnap_bmc_api/docs/TagAssignment.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of TagAssignment from a JSON string tag_assignment_instance = TagAssignment.from_json(json) # print the JSON string representation of the object -print TagAssignment.to_json() +print(TagAssignment.to_json()) # convert the object into a dict tag_assignment_dict = tag_assignment_instance.to_dict() # create an instance of TagAssignment from a dict -tag_assignment_form_dict = tag_assignment.from_dict(tag_assignment_dict) +tag_assignment_from_dict = TagAssignment.from_dict(tag_assignment_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/docs/TagAssignmentRequest.md b/pnap_bmc_api/docs/TagAssignmentRequest.md index 4c81da22..a171da71 100644 --- a/pnap_bmc_api/docs/TagAssignmentRequest.md +++ b/pnap_bmc_api/docs/TagAssignmentRequest.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of TagAssignmentRequest from a JSON string tag_assignment_request_instance = TagAssignmentRequest.from_json(json) # print the JSON string representation of the object -print TagAssignmentRequest.to_json() +print(TagAssignmentRequest.to_json()) # convert the object into a dict tag_assignment_request_dict = tag_assignment_request_instance.to_dict() # create an instance of TagAssignmentRequest from a dict -tag_assignment_request_form_dict = tag_assignment_request.from_dict(tag_assignment_request_dict) +tag_assignment_request_from_dict = TagAssignmentRequest.from_dict(tag_assignment_request_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_bmc_api/pnap_bmc_api/__init__.py b/pnap_bmc_api/pnap_bmc_api/__init__.py index 15955dc6..fda358c6 100644 --- a/pnap_bmc_api/pnap_bmc_api/__init__.py +++ b/pnap_bmc_api/pnap_bmc_api/__init__.py @@ -15,63 +15,123 @@ """ # noqa: E501 -__version__ = "2.2.1" +__version__ = "2.3.0" + +# Define package exports +__all__ = [ + "QuotasApi", + "SSHKeysApi", + "ServersApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "ActionResult", + "DeleteResult", + "DeleteSshKeyResult", + "Error", + "EsxiDatastoreConfiguration", + "EsxiOsConfiguration", + "GpuConfiguration", + "IpBlocksConfiguration", + "NetworkConfiguration", + "OsConfiguration", + "OsConfigurationCloudInit", + "OsConfigurationMap", + "OsConfigurationMapEsxi", + "OsConfigurationMapProxmox", + "OsConfigurationNetrisController", + "OsConfigurationNetrisSoftgate", + "OsConfigurationWindows", + "PrivateNetworkConfiguration", + "PublicNetworkConfiguration", + "Quota", + "QuotaEditLimitRequest", + "QuotaEditLimitRequestDetails", + "RelinquishIpBlock", + "ReservationTransferDetails", + "ResetResult", + "Server", + "ServerCreate", + "ServerIpBlock", + "ServerNetworkUpdate", + "ServerPatch", + "ServerPrivateNetwork", + "ServerProvision", + "ServerPublicNetwork", + "ServerReserve", + "ServerReset", + "SshKey", + "SshKeyCreate", + "SshKeyUpdate", + "StorageConfiguration", + "StorageConfigurationRootPartition", + "TagAssignment", + "TagAssignmentRequest", +] # import apis into sdk package -from pnap_bmc_api.api.quotas_api import QuotasApi -from pnap_bmc_api.api.ssh_keys_api import SSHKeysApi -from pnap_bmc_api.api.servers_api import ServersApi +from pnap_bmc_api.api.quotas_api import QuotasApi as QuotasApi +from pnap_bmc_api.api.ssh_keys_api import SSHKeysApi as SSHKeysApi +from pnap_bmc_api.api.servers_api import ServersApi as ServersApi # import ApiClient -from pnap_bmc_api.api_response import ApiResponse -from pnap_bmc_api.api_client import ApiClient -from pnap_bmc_api.configuration import Configuration -from pnap_bmc_api.exceptions import OpenApiException -from pnap_bmc_api.exceptions import ApiTypeError -from pnap_bmc_api.exceptions import ApiValueError -from pnap_bmc_api.exceptions import ApiKeyError -from pnap_bmc_api.exceptions import ApiAttributeError -from pnap_bmc_api.exceptions import ApiException +from pnap_bmc_api.api_response import ApiResponse as ApiResponse +from pnap_bmc_api.api_client import ApiClient as ApiClient +from pnap_bmc_api.configuration import Configuration as Configuration +from pnap_bmc_api.exceptions import OpenApiException as OpenApiException +from pnap_bmc_api.exceptions import ApiTypeError as ApiTypeError +from pnap_bmc_api.exceptions import ApiValueError as ApiValueError +from pnap_bmc_api.exceptions import ApiKeyError as ApiKeyError +from pnap_bmc_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_bmc_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_bmc_api.models.action_result import ActionResult -from pnap_bmc_api.models.delete_result import DeleteResult -from pnap_bmc_api.models.delete_ssh_key_result import DeleteSshKeyResult -from pnap_bmc_api.models.error import Error -from pnap_bmc_api.models.esxi_datastore_configuration import EsxiDatastoreConfiguration -from pnap_bmc_api.models.esxi_os_configuration import EsxiOsConfiguration -from pnap_bmc_api.models.gpu_configuration import GpuConfiguration -from pnap_bmc_api.models.ip_blocks_configuration import IpBlocksConfiguration -from pnap_bmc_api.models.network_configuration import NetworkConfiguration -from pnap_bmc_api.models.os_configuration import OsConfiguration -from pnap_bmc_api.models.os_configuration_cloud_init import OsConfigurationCloudInit -from pnap_bmc_api.models.os_configuration_map import OsConfigurationMap -from pnap_bmc_api.models.os_configuration_map_esxi import OsConfigurationMapEsxi -from pnap_bmc_api.models.os_configuration_map_proxmox import OsConfigurationMapProxmox -from pnap_bmc_api.models.os_configuration_netris_controller import OsConfigurationNetrisController -from pnap_bmc_api.models.os_configuration_netris_softgate import OsConfigurationNetrisSoftgate -from pnap_bmc_api.models.os_configuration_windows import OsConfigurationWindows -from pnap_bmc_api.models.private_network_configuration import PrivateNetworkConfiguration -from pnap_bmc_api.models.public_network_configuration import PublicNetworkConfiguration -from pnap_bmc_api.models.quota import Quota -from pnap_bmc_api.models.quota_edit_limit_request import QuotaEditLimitRequest -from pnap_bmc_api.models.quota_edit_limit_request_details import QuotaEditLimitRequestDetails -from pnap_bmc_api.models.relinquish_ip_block import RelinquishIpBlock -from pnap_bmc_api.models.reset_result import ResetResult -from pnap_bmc_api.models.server import Server -from pnap_bmc_api.models.server_create import ServerCreate -from pnap_bmc_api.models.server_ip_block import ServerIpBlock -from pnap_bmc_api.models.server_network_update import ServerNetworkUpdate -from pnap_bmc_api.models.server_patch import ServerPatch -from pnap_bmc_api.models.server_private_network import ServerPrivateNetwork -from pnap_bmc_api.models.server_provision import ServerProvision -from pnap_bmc_api.models.server_public_network import ServerPublicNetwork -from pnap_bmc_api.models.server_reserve import ServerReserve -from pnap_bmc_api.models.server_reset import ServerReset -from pnap_bmc_api.models.ssh_key import SshKey -from pnap_bmc_api.models.ssh_key_create import SshKeyCreate -from pnap_bmc_api.models.ssh_key_update import SshKeyUpdate -from pnap_bmc_api.models.storage_configuration import StorageConfiguration -from pnap_bmc_api.models.storage_configuration_root_partition import StorageConfigurationRootPartition -from pnap_bmc_api.models.tag_assignment import TagAssignment -from pnap_bmc_api.models.tag_assignment_request import TagAssignmentRequest +from pnap_bmc_api.models.action_result import ActionResult as ActionResult +from pnap_bmc_api.models.delete_result import DeleteResult as DeleteResult +from pnap_bmc_api.models.delete_ssh_key_result import DeleteSshKeyResult as DeleteSshKeyResult +from pnap_bmc_api.models.error import Error as Error +from pnap_bmc_api.models.esxi_datastore_configuration import EsxiDatastoreConfiguration as EsxiDatastoreConfiguration +from pnap_bmc_api.models.esxi_os_configuration import EsxiOsConfiguration as EsxiOsConfiguration +from pnap_bmc_api.models.gpu_configuration import GpuConfiguration as GpuConfiguration +from pnap_bmc_api.models.ip_blocks_configuration import IpBlocksConfiguration as IpBlocksConfiguration +from pnap_bmc_api.models.network_configuration import NetworkConfiguration as NetworkConfiguration +from pnap_bmc_api.models.os_configuration import OsConfiguration as OsConfiguration +from pnap_bmc_api.models.os_configuration_cloud_init import OsConfigurationCloudInit as OsConfigurationCloudInit +from pnap_bmc_api.models.os_configuration_map import OsConfigurationMap as OsConfigurationMap +from pnap_bmc_api.models.os_configuration_map_esxi import OsConfigurationMapEsxi as OsConfigurationMapEsxi +from pnap_bmc_api.models.os_configuration_map_proxmox import OsConfigurationMapProxmox as OsConfigurationMapProxmox +from pnap_bmc_api.models.os_configuration_netris_controller import OsConfigurationNetrisController as OsConfigurationNetrisController +from pnap_bmc_api.models.os_configuration_netris_softgate import OsConfigurationNetrisSoftgate as OsConfigurationNetrisSoftgate +from pnap_bmc_api.models.os_configuration_windows import OsConfigurationWindows as OsConfigurationWindows +from pnap_bmc_api.models.private_network_configuration import PrivateNetworkConfiguration as PrivateNetworkConfiguration +from pnap_bmc_api.models.public_network_configuration import PublicNetworkConfiguration as PublicNetworkConfiguration +from pnap_bmc_api.models.quota import Quota as Quota +from pnap_bmc_api.models.quota_edit_limit_request import QuotaEditLimitRequest as QuotaEditLimitRequest +from pnap_bmc_api.models.quota_edit_limit_request_details import QuotaEditLimitRequestDetails as QuotaEditLimitRequestDetails +from pnap_bmc_api.models.relinquish_ip_block import RelinquishIpBlock as RelinquishIpBlock +from pnap_bmc_api.models.reservation_transfer_details import ReservationTransferDetails as ReservationTransferDetails +from pnap_bmc_api.models.reset_result import ResetResult as ResetResult +from pnap_bmc_api.models.server import Server as Server +from pnap_bmc_api.models.server_create import ServerCreate as ServerCreate +from pnap_bmc_api.models.server_ip_block import ServerIpBlock as ServerIpBlock +from pnap_bmc_api.models.server_network_update import ServerNetworkUpdate as ServerNetworkUpdate +from pnap_bmc_api.models.server_patch import ServerPatch as ServerPatch +from pnap_bmc_api.models.server_private_network import ServerPrivateNetwork as ServerPrivateNetwork +from pnap_bmc_api.models.server_provision import ServerProvision as ServerProvision +from pnap_bmc_api.models.server_public_network import ServerPublicNetwork as ServerPublicNetwork +from pnap_bmc_api.models.server_reserve import ServerReserve as ServerReserve +from pnap_bmc_api.models.server_reset import ServerReset as ServerReset +from pnap_bmc_api.models.ssh_key import SshKey as SshKey +from pnap_bmc_api.models.ssh_key_create import SshKeyCreate as SshKeyCreate +from pnap_bmc_api.models.ssh_key_update import SshKeyUpdate as SshKeyUpdate +from pnap_bmc_api.models.storage_configuration import StorageConfiguration as StorageConfiguration +from pnap_bmc_api.models.storage_configuration_root_partition import StorageConfigurationRootPartition as StorageConfigurationRootPartition +from pnap_bmc_api.models.tag_assignment import TagAssignment as TagAssignment +from pnap_bmc_api.models.tag_assignment_request import TagAssignmentRequest as TagAssignmentRequest + diff --git a/pnap_bmc_api/pnap_bmc_api/api/quotas_api.py b/pnap_bmc_api/pnap_bmc_api/api/quotas_api.py index 8bc54c2e..aef9d4f4 100644 --- a/pnap_bmc_api/pnap_bmc_api/api/quotas_api.py +++ b/pnap_bmc_api/pnap_bmc_api/api/quotas_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Bare Metal Cloud API @@ -13,27 +11,18 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictStr +from pydantic import Field, StrictStr from typing import List - +from typing_extensions import Annotated from pnap_bmc_api.models.quota import Quota from pnap_bmc_api.models.quota_edit_limit_request import QuotaEditLimitRequest -from pnap_bmc_api.api_client import ApiClient +from pnap_bmc_api.api_client import ApiClient, RequestSerialized from pnap_bmc_api.api_response import ApiResponse from pnap_bmc_api.rest import RESTResponseType @@ -254,7 +243,7 @@ def _quotas_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -265,7 +254,9 @@ def _quotas_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -276,11 +267,12 @@ def _quotas_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -535,7 +527,7 @@ def _quotas_quota_id_actions_request_edit_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -546,7 +538,9 @@ def _quotas_quota_id_actions_request_edit_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -561,11 +555,12 @@ def _quotas_quota_id_actions_request_edit_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -820,7 +815,7 @@ def _quotas_quota_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -831,7 +826,9 @@ def _quotas_quota_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -844,11 +841,12 @@ def _quotas_quota_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting diff --git a/pnap_bmc_api/pnap_bmc_api/api/servers_api.py b/pnap_bmc_api/pnap_bmc_api/api/servers_api.py index edb4c552..1d30bd98 100644 --- a/pnap_bmc_api/pnap_bmc_api/api/servers_api.py +++ b/pnap_bmc_api/pnap_bmc_api/api/servers_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Bare Metal Cloud API @@ -13,26 +11,18 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictBool, StrictStr +from pydantic import Field, StrictBool, StrictStr from typing import List, Optional - +from typing_extensions import Annotated from pnap_bmc_api.models.action_result import ActionResult from pnap_bmc_api.models.delete_result import DeleteResult from pnap_bmc_api.models.relinquish_ip_block import RelinquishIpBlock +from pnap_bmc_api.models.reservation_transfer_details import ReservationTransferDetails from pnap_bmc_api.models.reset_result import ResetResult from pnap_bmc_api.models.server import Server from pnap_bmc_api.models.server_create import ServerCreate @@ -46,7 +36,7 @@ from pnap_bmc_api.models.server_reset import ServerReset from pnap_bmc_api.models.tag_assignment_request import TagAssignmentRequest -from pnap_bmc_api.api_client import ApiClient +from pnap_bmc_api.api_client import ApiClient, RequestSerialized from pnap_bmc_api.api_response import ApiResponse from pnap_bmc_api.rest import RESTResponseType @@ -296,7 +286,7 @@ def _delete_private_network_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -307,7 +297,9 @@ def _delete_private_network_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -322,11 +314,12 @@ def _delete_private_network_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -565,7 +558,7 @@ def _servers_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -577,7 +570,9 @@ def _servers_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -592,11 +587,12 @@ def _servers_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -857,7 +853,7 @@ def _servers_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -868,7 +864,9 @@ def _servers_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -885,11 +883,12 @@ def _servers_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1160,7 +1159,7 @@ def _servers_server_id_actions_deprovision_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1171,7 +1170,9 @@ def _servers_server_id_actions_deprovision_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1186,11 +1187,12 @@ def _servers_server_id_actions_deprovision_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1448,7 +1450,7 @@ def _servers_server_id_actions_power_off_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1459,7 +1461,9 @@ def _servers_server_id_actions_power_off_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1472,11 +1476,12 @@ def _servers_server_id_actions_power_off_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1721,7 +1726,7 @@ def _servers_server_id_actions_power_on_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1732,7 +1737,9 @@ def _servers_server_id_actions_power_on_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1745,11 +1752,12 @@ def _servers_server_id_actions_power_on_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -2023,7 +2031,7 @@ def _servers_server_id_actions_provision_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2034,7 +2042,9 @@ def _servers_server_id_actions_provision_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2053,11 +2063,12 @@ def _servers_server_id_actions_provision_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -2315,7 +2326,7 @@ def _servers_server_id_actions_reboot_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2326,7 +2337,9 @@ def _servers_server_id_actions_reboot_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2339,11 +2352,12 @@ def _servers_server_id_actions_reboot_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -2601,7 +2615,7 @@ def _servers_server_id_actions_reserve_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2612,7 +2626,9 @@ def _servers_server_id_actions_reserve_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2627,11 +2643,12 @@ def _servers_server_id_actions_reserve_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -2905,7 +2922,7 @@ def _servers_server_id_actions_reset_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2916,7 +2933,9 @@ def _servers_server_id_actions_reset_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2931,11 +2950,12 @@ def _servers_server_id_actions_reset_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -3193,7 +3213,7 @@ def _servers_server_id_actions_shutdown_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -3204,7 +3224,9 @@ def _servers_server_id_actions_shutdown_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -3217,12 +3239,317 @@ def _servers_server_id_actions_shutdown_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'OAuth2' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/servers/{serverId}/actions/shutdown', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def servers_server_id_actions_transfer_reservation( + self, + server_id: Annotated[StrictStr, Field(description="The server's ID.")], + reservation_transfer_details: ReservationTransferDetails, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> Server: + """Transfer server reservation. + + Transfer server reservation. An active (READY) reservation can be transferred from a server in ERROR or RESERVED status to another HOURLY provisioned server of the same location and type. + + :param server_id: The server's ID. (required) + :type server_id: str + :param reservation_transfer_details: (required) + :type reservation_transfer_details: ReservationTransferDetails + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._servers_server_id_actions_transfer_reservation_serialize( + server_id=server_id, + reservation_transfer_details=reservation_transfer_details, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "Server", + '400': "Error", + '401': "Error", + '403': "Error", + '409': "Error", + '500': "Error", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def servers_server_id_actions_transfer_reservation_with_http_info( + self, + server_id: Annotated[StrictStr, Field(description="The server's ID.")], + reservation_transfer_details: ReservationTransferDetails, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[Server]: + """Transfer server reservation. + + Transfer server reservation. An active (READY) reservation can be transferred from a server in ERROR or RESERVED status to another HOURLY provisioned server of the same location and type. + + :param server_id: The server's ID. (required) + :type server_id: str + :param reservation_transfer_details: (required) + :type reservation_transfer_details: ReservationTransferDetails + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._servers_server_id_actions_transfer_reservation_serialize( + server_id=server_id, + reservation_transfer_details=reservation_transfer_details, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "Server", + '400': "Error", + '401': "Error", + '403': "Error", + '409': "Error", + '500': "Error", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def servers_server_id_actions_transfer_reservation_without_preload_content( + self, + server_id: Annotated[StrictStr, Field(description="The server's ID.")], + reservation_transfer_details: ReservationTransferDetails, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Transfer server reservation. + + Transfer server reservation. An active (READY) reservation can be transferred from a server in ERROR or RESERVED status to another HOURLY provisioned server of the same location and type. + + :param server_id: The server's ID. (required) + :type server_id: str + :param reservation_transfer_details: (required) + :type reservation_transfer_details: ReservationTransferDetails + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._servers_server_id_actions_transfer_reservation_serialize( + server_id=server_id, + reservation_transfer_details=reservation_transfer_details, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "Server", + '400': "Error", + '401': "Error", + '403': "Error", + '409': "Error", + '500': "Error", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout ) + return response_data.response + + + def _servers_server_id_actions_transfer_reservation_serialize( + self, + server_id, + reservation_transfer_details, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + # process the path parameters + if server_id is not None: + _path_params['serverId'] = server_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if reservation_transfer_details is not None: + _body_params = reservation_transfer_details + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type # authentication setting _auth_settings: List[str] = [ @@ -3231,7 +3558,7 @@ def _servers_server_id_actions_shutdown_post_serialize( return self.api_client.param_serialize( method='POST', - resource_path='/servers/{serverId}/actions/shutdown', + resource_path='/servers/{serverId}/actions/transfer-reservation', path_params=_path_params, query_params=_query_params, header_params=_header_params, @@ -3466,7 +3793,7 @@ def _servers_server_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -3477,7 +3804,9 @@ def _servers_server_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -3490,11 +3819,12 @@ def _servers_server_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -3736,7 +4066,7 @@ def _servers_server_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -3747,7 +4077,9 @@ def _servers_server_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -3760,11 +4092,12 @@ def _servers_server_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -4035,7 +4368,7 @@ def _servers_server_id_ip_blocks_ip_block_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -4046,7 +4379,9 @@ def _servers_server_id_ip_blocks_ip_block_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -4063,11 +4398,12 @@ def _servers_server_id_ip_blocks_ip_block_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -4338,7 +4674,7 @@ def _servers_server_id_ip_blocks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -4349,7 +4685,9 @@ def _servers_server_id_ip_blocks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -4364,11 +4702,12 @@ def _servers_server_id_ip_blocks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -4636,7 +4975,7 @@ def _servers_server_id_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -4647,7 +4986,9 @@ def _servers_server_id_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -4662,11 +5003,12 @@ def _servers_server_id_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -4963,7 +5305,7 @@ def _servers_server_id_private_networks_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -4974,7 +5316,9 @@ def _servers_server_id_private_networks_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -4995,11 +5339,12 @@ def _servers_server_id_private_networks_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -5280,7 +5625,7 @@ def _servers_server_id_private_networks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -5291,7 +5636,9 @@ def _servers_server_id_private_networks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -5310,11 +5657,12 @@ def _servers_server_id_private_networks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -5585,7 +5933,7 @@ def _servers_server_id_public_networks_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -5596,7 +5944,9 @@ def _servers_server_id_public_networks_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -5611,11 +5961,12 @@ def _servers_server_id_public_networks_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -5899,7 +6250,7 @@ def _servers_server_id_public_networks_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -5910,7 +6261,9 @@ def _servers_server_id_public_networks_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -5931,11 +6284,12 @@ def _servers_server_id_public_networks_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -6219,7 +6573,7 @@ def _servers_server_id_public_networks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -6230,7 +6584,9 @@ def _servers_server_id_public_networks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -6249,11 +6605,12 @@ def _servers_server_id_public_networks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -6521,7 +6878,7 @@ def _servers_server_id_tags_put_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -6533,7 +6890,9 @@ def _servers_server_id_tags_put_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -6548,11 +6907,12 @@ def _servers_server_id_tags_put_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_bmc_api/pnap_bmc_api/api/ssh_keys_api.py b/pnap_bmc_api/pnap_bmc_api/api/ssh_keys_api.py index beb94ed5..db2080bf 100644 --- a/pnap_bmc_api/pnap_bmc_api/api/ssh_keys_api.py +++ b/pnap_bmc_api/pnap_bmc_api/api/ssh_keys_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Bare Metal Cloud API @@ -13,29 +11,20 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictStr +from pydantic import Field, StrictStr from typing import List - +from typing_extensions import Annotated from pnap_bmc_api.models.delete_ssh_key_result import DeleteSshKeyResult from pnap_bmc_api.models.ssh_key import SshKey from pnap_bmc_api.models.ssh_key_create import SshKeyCreate from pnap_bmc_api.models.ssh_key_update import SshKeyUpdate -from pnap_bmc_api.api_client import ApiClient +from pnap_bmc_api.api_client import ApiClient, RequestSerialized from pnap_bmc_api.api_response import ApiResponse from pnap_bmc_api.rest import RESTResponseType @@ -253,7 +242,7 @@ def _ssh_keys_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -264,7 +253,9 @@ def _ssh_keys_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -275,11 +266,12 @@ def _ssh_keys_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -524,7 +516,7 @@ def _ssh_keys_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -535,7 +527,9 @@ def _ssh_keys_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -548,11 +542,12 @@ def _ssh_keys_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -807,7 +802,7 @@ def _ssh_keys_ssh_key_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -818,7 +813,9 @@ def _ssh_keys_ssh_key_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -831,11 +828,12 @@ def _ssh_keys_ssh_key_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1077,7 +1075,7 @@ def _ssh_keys_ssh_key_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1088,7 +1086,9 @@ def _ssh_keys_ssh_key_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1101,11 +1101,12 @@ def _ssh_keys_ssh_key_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1366,7 +1367,7 @@ def _ssh_keys_ssh_key_id_put_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1377,7 +1378,9 @@ def _ssh_keys_ssh_key_id_put_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1392,11 +1395,12 @@ def _ssh_keys_ssh_key_id_put_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_bmc_api/pnap_bmc_api/api_client.py b/pnap_bmc_api/pnap_bmc_api/api_client.py index 47f759bb..5ca259a4 100644 --- a/pnap_bmc_api/pnap_bmc_api/api_client.py +++ b/pnap_bmc_api/pnap_bmc_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Bare Metal Cloud API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_bmc_api.configuration import Configuration -from pnap_bmc_api.api_response import ApiResponse +from pnap_bmc_api.api_response import ApiResponse, T as ApiResponseT import pnap_bmc_api.models from pnap_bmc_api import rest from pnap_bmc_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_bmc_api/2.2.1" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_bmc_api/2.3.0" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_bmc_api/2.2.1" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_bmc_api/2.3.0" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_bmc_api/pnap_bmc_api/api_response.py b/pnap_bmc_api/pnap_bmc_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_bmc_api/pnap_bmc_api/api_response.py +++ b/pnap_bmc_api/pnap_bmc_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_bmc_api/pnap_bmc_api/configuration.py b/pnap_bmc_api/pnap_bmc_api/configuration.py index 35159a65..d8f18adf 100644 --- a/pnap_bmc_api/pnap_bmc_api/configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Bare Metal Cloud API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/bmc/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 0.1\n"\ - "SDK Package Version: 2.2.1".\ + "SDK Package Version: 2.3.0".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_bmc_api/pnap_bmc_api/exceptions.py b/pnap_bmc_api/pnap_bmc_api/exceptions.py index c4bf9133..ba48d6e5 100644 --- a/pnap_bmc_api/pnap_bmc_api/exceptions.py +++ b/pnap_bmc_api/pnap_bmc_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Bare Metal Cloud API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_bmc_api/pnap_bmc_api/models/__init__.py b/pnap_bmc_api/pnap_bmc_api/models/__init__.py index 8990c62b..28ce1380 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/__init__.py +++ b/pnap_bmc_api/pnap_bmc_api/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_bmc_api.models.action_result import ActionResult from pnap_bmc_api.models.delete_result import DeleteResult @@ -38,6 +37,7 @@ from pnap_bmc_api.models.quota_edit_limit_request import QuotaEditLimitRequest from pnap_bmc_api.models.quota_edit_limit_request_details import QuotaEditLimitRequestDetails from pnap_bmc_api.models.relinquish_ip_block import RelinquishIpBlock +from pnap_bmc_api.models.reservation_transfer_details import ReservationTransferDetails from pnap_bmc_api.models.reset_result import ResetResult from pnap_bmc_api.models.server import Server from pnap_bmc_api.models.server_create import ServerCreate @@ -56,3 +56,4 @@ from pnap_bmc_api.models.storage_configuration_root_partition import StorageConfigurationRootPartition from pnap_bmc_api.models.tag_assignment import TagAssignment from pnap_bmc_api.models.tag_assignment_request import TagAssignmentRequest + diff --git a/pnap_bmc_api/pnap_bmc_api/models/action_result.py b/pnap_bmc_api/pnap_bmc_api/models/action_result.py index b6d59bb2..d2a822f9 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/action_result.py +++ b/pnap_bmc_api/pnap_bmc_api/models/action_result.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ActionResult(BaseModel): """ @@ -35,11 +31,11 @@ class ActionResult(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["result"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +48,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ActionResult from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +63,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -82,7 +80,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ActionResult from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/delete_result.py b/pnap_bmc_api/pnap_bmc_api/models/delete_result.py index 939fd0cd..26bc531a 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/delete_result.py +++ b/pnap_bmc_api/pnap_bmc_api/models/delete_result.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class DeleteResult(BaseModel): """ @@ -36,11 +32,11 @@ class DeleteResult(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["result", "serverId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of DeleteResult from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of DeleteResult from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/delete_ssh_key_result.py b/pnap_bmc_api/pnap_bmc_api/models/delete_ssh_key_result.py index 1f106c87..48f96ce4 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/delete_ssh_key_result.py +++ b/pnap_bmc_api/pnap_bmc_api/models/delete_ssh_key_result.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class DeleteSshKeyResult(BaseModel): """ @@ -36,11 +32,11 @@ class DeleteSshKeyResult(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["result", "sshKeyId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of DeleteSshKeyResult from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of DeleteSshKeyResult from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/error.py b/pnap_bmc_api/pnap_bmc_api/models/error.py index 6f33426e..3afd9cc4 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/error.py +++ b/pnap_bmc_api/pnap_bmc_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/esxi_datastore_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/esxi_datastore_configuration.py index 0baff6f5..35ad3e8d 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/esxi_datastore_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/esxi_datastore_configuration.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class EsxiDatastoreConfiguration(BaseModel): """ @@ -43,11 +39,11 @@ def datastore_name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^[a-zA-Z0-9]+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -60,7 +56,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of EsxiDatastoreConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -75,11 +71,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -90,7 +88,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of EsxiDatastoreConfiguration from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/esxi_os_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/esxi_os_configuration.py index 43ee272f..e68fccae 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/esxi_os_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/esxi_os_configuration.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel -from pydantic import Field from pnap_bmc_api.models.esxi_datastore_configuration import EsxiDatastoreConfiguration -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class EsxiOsConfiguration(BaseModel): """ @@ -36,11 +32,11 @@ class EsxiOsConfiguration(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["datastoreConfiguration"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of EsxiOsConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of datastore_configuration @@ -86,7 +84,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of EsxiOsConfiguration from a dict""" if obj is None: return None @@ -95,7 +93,7 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "datastoreConfiguration": EsxiDatastoreConfiguration.from_dict(obj.get("datastoreConfiguration")) if obj.get("datastoreConfiguration") is not None else None + "datastoreConfiguration": EsxiDatastoreConfiguration.from_dict(obj["datastoreConfiguration"]) if obj.get("datastoreConfiguration") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/gpu_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/gpu_configuration.py index 80051fca..7723b8c9 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/gpu_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/gpu_configuration.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class GpuConfiguration(BaseModel): """ @@ -36,11 +32,11 @@ class GpuConfiguration(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["longName", "count"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of GpuConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of GpuConfiguration from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/ip_blocks_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/ip_blocks_configuration.py index 68f0c5f5..62cf9097 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/ip_blocks_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/ip_blocks_configuration.py @@ -18,23 +18,19 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_bmc_api.models.server_ip_block import ServerIpBlock -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class IpBlocksConfiguration(BaseModel): """ The IP blocks to assign to this server. This is an exclusive allocation, i.e. the IP blocks cannot be shared with other servers. If IpBlocksConfiguration is not defined, the purchase of a new IP block is determined by the networkType field. """ # noqa: E501 configuration_type: Optional[StrictStr] = Field(default='PURCHASE_NEW', description="(Write-only) Determines the approach for configuring IP blocks for the server being provisioned. If PURCHASE_NEW is selected, the smallest supported range, depending on the operating system, is allocated to the server.", alias="configurationType") - ip_blocks: Optional[Annotated[List[ServerIpBlock], Field(max_length=1)]] = Field(default=None, description="Used to specify the previously purchased IP blocks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType.", alias="ipBlocks") + ip_blocks: Optional[Annotated[List[ServerIpBlock], Field(max_length=1)]] = Field(default=None, description="Used for specifying the previously purchased IPv4 blocks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType.", alias="ipBlocks") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["configurationType", "ipBlocks"] @@ -44,15 +40,15 @@ def configuration_type_validate_enum(cls, value): if value is None: return value - if value not in ('PURCHASE_NEW', 'USER_DEFINED', 'NONE'): + if value not in set(['PURCHASE_NEW', 'USER_DEFINED', 'NONE']): raise ValueError("must be one of enum values ('PURCHASE_NEW', 'USER_DEFINED', 'NONE')") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -65,7 +61,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of IpBlocksConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -80,19 +76,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in ip_blocks (list) _items = [] if self.ip_blocks: - for _item in self.ip_blocks: - if _item: - _items.append(_item.to_dict()) + for _item_ip_blocks in self.ip_blocks: + if _item_ip_blocks: + _items.append(_item_ip_blocks.to_dict()) _dict['ipBlocks'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -102,7 +100,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of IpBlocksConfiguration from a dict""" if obj is None: return None @@ -112,7 +110,7 @@ def from_dict(cls, obj: Dict) -> Self: _obj = cls.model_validate({ "configurationType": obj.get("configurationType") if obj.get("configurationType") is not None else 'PURCHASE_NEW', - "ipBlocks": [ServerIpBlock.from_dict(_item) for _item in obj.get("ipBlocks")] if obj.get("ipBlocks") is not None else None + "ipBlocks": [ServerIpBlock.from_dict(_item) for _item in obj["ipBlocks"]] if obj.get("ipBlocks") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/network_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/network_configuration.py index 781482c8..c745cff5 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/network_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/network_configuration.py @@ -18,17 +18,13 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from pnap_bmc_api.models.ip_blocks_configuration import IpBlocksConfiguration from pnap_bmc_api.models.private_network_configuration import PrivateNetworkConfiguration from pnap_bmc_api.models.public_network_configuration import PublicNetworkConfiguration -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class NetworkConfiguration(BaseModel): """ @@ -41,11 +37,11 @@ class NetworkConfiguration(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["gatewayAddress", "privateNetworkConfiguration", "ipBlocksConfiguration", "publicNetworkConfiguration"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -58,7 +54,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of NetworkConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -73,11 +69,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of private_network_configuration @@ -97,7 +95,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of NetworkConfiguration from a dict""" if obj is None: return None @@ -107,9 +105,9 @@ def from_dict(cls, obj: Dict) -> Self: _obj = cls.model_validate({ "gatewayAddress": obj.get("gatewayAddress"), - "privateNetworkConfiguration": PrivateNetworkConfiguration.from_dict(obj.get("privateNetworkConfiguration")) if obj.get("privateNetworkConfiguration") is not None else None, - "ipBlocksConfiguration": IpBlocksConfiguration.from_dict(obj.get("ipBlocksConfiguration")) if obj.get("ipBlocksConfiguration") is not None else None, - "publicNetworkConfiguration": PublicNetworkConfiguration.from_dict(obj.get("publicNetworkConfiguration")) if obj.get("publicNetworkConfiguration") is not None else None + "privateNetworkConfiguration": PrivateNetworkConfiguration.from_dict(obj["privateNetworkConfiguration"]) if obj.get("privateNetworkConfiguration") is not None else None, + "ipBlocksConfiguration": IpBlocksConfiguration.from_dict(obj["ipBlocksConfiguration"]) if obj.get("ipBlocksConfiguration") is not None else None, + "publicNetworkConfiguration": PublicNetworkConfiguration.from_dict(obj["publicNetworkConfiguration"]) if obj.get("publicNetworkConfiguration") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration.py index cbdaa590..6908311a 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration.py @@ -18,20 +18,16 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field from typing_extensions import Annotated from pnap_bmc_api.models.esxi_os_configuration import EsxiOsConfiguration from pnap_bmc_api.models.os_configuration_cloud_init import OsConfigurationCloudInit from pnap_bmc_api.models.os_configuration_netris_controller import OsConfigurationNetrisController from pnap_bmc_api.models.os_configuration_netris_softgate import OsConfigurationNetrisSoftgate from pnap_bmc_api.models.os_configuration_windows import OsConfigurationWindows -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfiguration(BaseModel): """ @@ -49,11 +45,11 @@ class OsConfiguration(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["netrisController", "netrisSoftgate", "windows", "rootPassword", "managementUiUrl", "managementAccessAllowedIps", "installOsToRam", "esxi", "cloudInit"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +62,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -83,13 +79,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "root_password", + "management_ui_url", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "root_password", - "management_ui_url", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of netris_controller @@ -115,7 +113,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfiguration from a dict""" if obj is None: return None @@ -124,15 +122,15 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "netrisController": OsConfigurationNetrisController.from_dict(obj.get("netrisController")) if obj.get("netrisController") is not None else None, - "netrisSoftgate": OsConfigurationNetrisSoftgate.from_dict(obj.get("netrisSoftgate")) if obj.get("netrisSoftgate") is not None else None, - "windows": OsConfigurationWindows.from_dict(obj.get("windows")) if obj.get("windows") is not None else None, + "netrisController": OsConfigurationNetrisController.from_dict(obj["netrisController"]) if obj.get("netrisController") is not None else None, + "netrisSoftgate": OsConfigurationNetrisSoftgate.from_dict(obj["netrisSoftgate"]) if obj.get("netrisSoftgate") is not None else None, + "windows": OsConfigurationWindows.from_dict(obj["windows"]) if obj.get("windows") is not None else None, "rootPassword": obj.get("rootPassword"), "managementUiUrl": obj.get("managementUiUrl"), "managementAccessAllowedIps": obj.get("managementAccessAllowedIps"), "installOsToRam": obj.get("installOsToRam") if obj.get("installOsToRam") is not None else False, - "esxi": EsxiOsConfiguration.from_dict(obj.get("esxi")) if obj.get("esxi") is not None else None, - "cloudInit": OsConfigurationCloudInit.from_dict(obj.get("cloudInit")) if obj.get("cloudInit") is not None else None + "esxi": EsxiOsConfiguration.from_dict(obj["esxi"]) if obj.get("esxi") is not None else None, + "cloudInit": OsConfigurationCloudInit.from_dict(obj["cloudInit"]) if obj.get("cloudInit") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_cloud_init.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_cloud_init.py index e92e73fb..dc66840b 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_cloud_init.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_cloud_init.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBytes, StrictStr from typing import Any, ClassVar, Dict, List, Optional, Union -from pydantic import BaseModel, StrictBytes, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfigurationCloudInit(BaseModel): """ @@ -35,11 +31,11 @@ class OsConfigurationCloudInit(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["userData"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +48,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfigurationCloudInit from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +63,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -82,7 +80,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfigurationCloudInit from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map.py index 55c0a56a..80b4bcf5 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map.py @@ -18,16 +18,13 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel from pnap_bmc_api.models.os_configuration_map_esxi import OsConfigurationMapEsxi from pnap_bmc_api.models.os_configuration_map_proxmox import OsConfigurationMapProxmox from pnap_bmc_api.models.os_configuration_windows import OsConfigurationWindows -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfigurationMap(BaseModel): """ @@ -39,11 +36,11 @@ class OsConfigurationMap(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["windows", "esxi", "proxmox"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -56,7 +53,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfigurationMap from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -71,11 +68,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of windows @@ -95,7 +94,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfigurationMap from a dict""" if obj is None: return None @@ -104,9 +103,9 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "windows": OsConfigurationWindows.from_dict(obj.get("windows")) if obj.get("windows") is not None else None, - "esxi": OsConfigurationMapEsxi.from_dict(obj.get("esxi")) if obj.get("esxi") is not None else None, - "proxmox": OsConfigurationMapProxmox.from_dict(obj.get("proxmox")) if obj.get("proxmox") is not None else None + "windows": OsConfigurationWindows.from_dict(obj["windows"]) if obj.get("windows") is not None else None, + "esxi": OsConfigurationMapEsxi.from_dict(obj["esxi"]) if obj.get("esxi") is not None else None, + "proxmox": OsConfigurationMapProxmox.from_dict(obj["proxmox"]) if obj.get("proxmox") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_esxi.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_esxi.py index 9425225d..1b895a8d 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_esxi.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_esxi.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfigurationMapEsxi(BaseModel): """ @@ -38,11 +34,11 @@ class OsConfigurationMapEsxi(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["rootPassword", "managementUiUrl", "managementAccessAllowedIps"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +51,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfigurationMapEsxi from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -72,13 +68,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "root_password", + "management_ui_url", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "root_password", - "management_ui_url", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -89,7 +87,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfigurationMapEsxi from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_proxmox.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_proxmox.py index e01b553c..f93cfa4e 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_proxmox.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_map_proxmox.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfigurationMapProxmox(BaseModel): """ @@ -38,11 +34,11 @@ class OsConfigurationMapProxmox(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["rootPassword", "managementUiUrl", "managementAccessAllowedIps"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +51,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfigurationMapProxmox from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -72,13 +68,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "root_password", + "management_ui_url", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "root_password", - "management_ui_url", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -89,7 +87,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfigurationMapProxmox from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_controller.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_controller.py index f59cf82d..8285ee63 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_controller.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_controller.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfigurationNetrisController(BaseModel): """ @@ -37,11 +33,11 @@ class OsConfigurationNetrisController(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["hostOs", "netrisWebConsoleUrl", "netrisUserPassword"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfigurationNetrisController from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -72,14 +68,16 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "host_os", + "netris_web_console_url", + "netris_user_password", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "host_os", - "netris_web_console_url", - "netris_user_password", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -90,7 +88,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfigurationNetrisController from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_softgate.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_softgate.py index d3f719ea..b2b1b5e6 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_softgate.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_netris_softgate.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfigurationNetrisSoftgate(BaseModel): """ @@ -59,11 +55,11 @@ def controller_auth_key_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^\S+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -76,7 +72,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfigurationNetrisSoftgate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -92,12 +88,14 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "host_os", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "host_os", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -108,7 +106,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfigurationNetrisSoftgate from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_windows.py b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_windows.py index bff90cb4..568e2ee3 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/os_configuration_windows.py +++ b/pnap_bmc_api/pnap_bmc_api/models/os_configuration_windows.py @@ -18,29 +18,26 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class OsConfigurationWindows(BaseModel): """ Windows OS configuration properties. """ # noqa: E501 rdp_allowed_ips: Optional[Annotated[List[StrictStr], Field(min_length=1)]] = Field(default=None, description="List of IPs allowed for RDP access to Windows OS. Supported in single IP, CIDR and range format. When undefined, RDP is disabled. To allow RDP access from any IP use 0.0.0.0/0. This will only be returned in response to provisioning a server.", alias="rdpAllowedIps") + bring_your_own_license: Optional[StrictBool] = Field(default=False, description="Use a Bring Your Own (BYO) Windows license. If true, the server is provisioned in trial mode, and you must activate your own license. If false (default), the server includes a managed Windows license billed by the platform. ", alias="bringYourOwnLicense") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["rdpAllowedIps"] + __properties: ClassVar[List[str]] = ["rdpAllowedIps", "bringYourOwnLicense"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of OsConfigurationWindows from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of OsConfigurationWindows from a dict""" if obj is None: return None @@ -92,7 +91,8 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "rdpAllowedIps": obj.get("rdpAllowedIps") + "rdpAllowedIps": obj.get("rdpAllowedIps"), + "bringYourOwnLicense": obj.get("bringYourOwnLicense") if obj.get("bringYourOwnLicense") is not None else False }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/private_network_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/private_network_configuration.py index 0379d93f..01469b0c 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/private_network_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/private_network_configuration.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from pnap_bmc_api.models.server_private_network import ServerPrivateNetwork -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PrivateNetworkConfiguration(BaseModel): """ @@ -34,15 +30,15 @@ class PrivateNetworkConfiguration(BaseModel): """ # noqa: E501 gateway_address: Optional[StrictStr] = Field(default=None, description="Deprecated in favour of a common gateway address across all networks available under NetworkConfiguration.
The address of the gateway assigned / to assign to the server.
When used as part of request body, IP address has to be part of private network assigned to this server.
Gateway address also has to be assigned on an already deployed resource unless the `force` query parameter is true.", alias="gatewayAddress") configuration_type: Optional[StrictStr] = Field(default='USE_OR_CREATE_DEFAULT', description="(Write-only) Determines the approach for configuring private network(s) for the server being provisioned. Currently this field should be set to `USE_OR_CREATE_DEFAULT`, `USER_DEFINED` or `NONE`.", alias="configurationType") - private_networks: Optional[List[ServerPrivateNetwork]] = Field(default=None, description="The list of private networks this server is member of. When this field is part of request body, it'll be used to specify the private networks to assign to this server upon provisioning. Used alongside the `USER_DEFINED` configurationType.", alias="privateNetworks") + private_networks: Optional[List[ServerPrivateNetwork]] = Field(default=None, description="The list of private networks this server belongs to. If this field is part of a request body, it will be used for specifying the private networks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType.", alias="privateNetworks") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["gatewayAddress", "configurationType", "privateNetworks"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +51,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PrivateNetworkConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,19 +66,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in private_networks (list) _items = [] if self.private_networks: - for _item in self.private_networks: - if _item: - _items.append(_item.to_dict()) + for _item_private_networks in self.private_networks: + if _item_private_networks: + _items.append(_item_private_networks.to_dict()) _dict['privateNetworks'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -92,7 +90,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PrivateNetworkConfiguration from a dict""" if obj is None: return None @@ -103,7 +101,7 @@ def from_dict(cls, obj: Dict) -> Self: _obj = cls.model_validate({ "gatewayAddress": obj.get("gatewayAddress"), "configurationType": obj.get("configurationType") if obj.get("configurationType") is not None else 'USE_OR_CREATE_DEFAULT', - "privateNetworks": [ServerPrivateNetwork.from_dict(_item) for _item in obj.get("privateNetworks")] if obj.get("privateNetworks") is not None else None + "privateNetworks": [ServerPrivateNetwork.from_dict(_item) for _item in obj["privateNetworks"]] if obj.get("privateNetworks") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/public_network_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/public_network_configuration.py index 2724de2e..653fa2b2 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/public_network_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/public_network_configuration.py @@ -18,29 +18,25 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel -from pydantic import Field from pnap_bmc_api.models.server_public_network import ServerPublicNetwork -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PublicNetworkConfiguration(BaseModel): """ Public network details of bare metal server. """ # noqa: E501 - public_networks: Optional[List[ServerPublicNetwork]] = Field(default=None, description="The list of public networks this server is member of. When this field is part of request body, it'll be used to specify the public networks to assign to this server upon provisioning.", alias="publicNetworks") + public_networks: Optional[List[ServerPublicNetwork]] = Field(default=None, description="The list of public networks this server belongs to. If this field is part of a request body, it will be used for specifying the public networks to assign to this server on provision. Only IPv4 addresses can be specified.", alias="publicNetworks") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["publicNetworks"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PublicNetworkConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,19 +64,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in public_networks (list) _items = [] if self.public_networks: - for _item in self.public_networks: - if _item: - _items.append(_item.to_dict()) + for _item_public_networks in self.public_networks: + if _item_public_networks: + _items.append(_item_public_networks.to_dict()) _dict['publicNetworks'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -90,7 +88,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PublicNetworkConfiguration from a dict""" if obj is None: return None @@ -99,7 +97,7 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "publicNetworks": [ServerPublicNetwork.from_dict(_item) for _item in obj.get("publicNetworks")] if obj.get("publicNetworks") is not None else None + "publicNetworks": [ServerPublicNetwork.from_dict(_item) for _item in obj["publicNetworks"]] if obj.get("publicNetworks") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/quota.py b/pnap_bmc_api/pnap_bmc_api/models/quota.py index 57513fe5..092b5bf5 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/quota.py +++ b/pnap_bmc_api/pnap_bmc_api/models/quota.py @@ -18,16 +18,12 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_bmc_api.models.quota_edit_limit_request_details import QuotaEditLimitRequestDetails -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Quota(BaseModel): """ @@ -47,15 +43,15 @@ class Quota(BaseModel): @field_validator('status') def status_validate_enum(cls, value): """Validates the enum""" - if value not in ('WITHIN_LIMIT', 'OVER_LIMIT', 'ON_LIMIT'): + if value not in set(['WITHIN_LIMIT', 'OVER_LIMIT', 'ON_LIMIT']): raise ValueError("must be one of enum values ('WITHIN_LIMIT', 'OVER_LIMIT', 'ON_LIMIT')") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -68,7 +64,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Quota from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -84,20 +80,22 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "quota_edit_limit_request_details", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "quota_edit_limit_request_details", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in quota_edit_limit_request_details (list) _items = [] if self.quota_edit_limit_request_details: - for _item in self.quota_edit_limit_request_details: - if _item: - _items.append(_item.to_dict()) + for _item_quota_edit_limit_request_details in self.quota_edit_limit_request_details: + if _item_quota_edit_limit_request_details: + _items.append(_item_quota_edit_limit_request_details.to_dict()) _dict['quotaEditLimitRequestDetails'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -107,7 +105,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Quota from a dict""" if obj is None: return None @@ -123,7 +121,7 @@ def from_dict(cls, obj: Dict) -> Self: "limit": obj.get("limit"), "unit": obj.get("unit"), "used": obj.get("used"), - "quotaEditLimitRequestDetails": [QuotaEditLimitRequestDetails.from_dict(_item) for _item in obj.get("quotaEditLimitRequestDetails")] if obj.get("quotaEditLimitRequestDetails") is not None else None + "quotaEditLimitRequestDetails": [QuotaEditLimitRequestDetails.from_dict(_item) for _item in obj["quotaEditLimitRequestDetails"]] if obj.get("quotaEditLimitRequestDetails") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request.py b/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request.py index 5e9e84fc..338f9ba2 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request.py +++ b/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class QuotaEditLimitRequest(BaseModel): """ @@ -40,15 +36,15 @@ class QuotaEditLimitRequest(BaseModel): @field_validator('reason') def reason_validate_regular_expression(cls, value): """Validates the regular expression""" - if not re.match(r"^(?!\s*$).+", value, re.DOTALL): - raise ValueError(r"must validate the regular expression /^(?s)(?!\s*$).+/") + if not re.match(r"(?s)^(?!\s*$).+", value): + raise ValueError("must validate the regular expression /^(?s)(?!\s*$).+/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -61,7 +57,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of QuotaEditLimitRequest from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -76,11 +72,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -91,7 +89,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of QuotaEditLimitRequest from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request_details.py b/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request_details.py index d122f989..6a29524a 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request_details.py +++ b/pnap_bmc_api/pnap_bmc_api/models/quota_edit_limit_request_details.py @@ -19,14 +19,11 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class QuotaEditLimitRequestDetails(BaseModel): """ @@ -41,15 +38,15 @@ class QuotaEditLimitRequestDetails(BaseModel): @field_validator('reason') def reason_validate_regular_expression(cls, value): """Validates the regular expression""" - if not re.match(r"^(?!\s*$).+", value, re.DOTALL): - raise ValueError(r"must validate the regular expression /^(?s)(?!\s*$).+/") + if not re.match(r"(?s)^(?!\s*$).+", value): + raise ValueError("must validate the regular expression /^(?s)(?!\s*$).+/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -62,7 +59,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of QuotaEditLimitRequestDetails from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -77,11 +74,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -92,7 +91,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of QuotaEditLimitRequestDetails from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/relinquish_ip_block.py b/pnap_bmc_api/pnap_bmc_api/models/relinquish_ip_block.py index 35413b8f..9e5d0030 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/relinquish_ip_block.py +++ b/pnap_bmc_api/pnap_bmc_api/models/relinquish_ip_block.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class RelinquishIpBlock(BaseModel): """ @@ -35,11 +31,11 @@ class RelinquishIpBlock(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["deleteIpBlocks"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +48,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of RelinquishIpBlock from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +63,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -82,7 +80,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of RelinquishIpBlock from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/reservation_transfer_details.py b/pnap_bmc_api/pnap_bmc_api/models/reservation_transfer_details.py new file mode 100644 index 00000000..6358a5fa --- /dev/null +++ b/pnap_bmc_api/pnap_bmc_api/models/reservation_transfer_details.py @@ -0,0 +1,101 @@ +# coding: utf-8 + +""" + Bare Metal Cloud API + + Create, power off, power on, reset, reboot, or shut down your server with the Bare Metal Cloud API. Deprovision servers, get or edit SSH key details, assign public IPs, assign servers to networks and a lot more. Manage your infrastructure more efficiently using just a few simple API calls.

Knowledge base articles to help you can be found here

All URLs are relative to (https://api.phoenixnap.com/bmc/v1/) + + The version of the OpenAPI document: 0.1 + Contact: support@phoenixnap.com + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class ReservationTransferDetails(BaseModel): + """ + Reservation transfer details. + """ # noqa: E501 + target_server_id: StrictStr = Field(description="ID of target server to transfer reservation to.", alias="targetServerId") + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["targetServerId"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of ReservationTransferDetails from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of ReservationTransferDetails from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "targetServerId": obj.get("targetServerId") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/pnap_bmc_api/pnap_bmc_api/models/reset_result.py b/pnap_bmc_api/pnap_bmc_api/models/reset_result.py index 1a971db5..0a150ce4 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/reset_result.py +++ b/pnap_bmc_api/pnap_bmc_api/models/reset_result.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from pnap_bmc_api.models.os_configuration_map import OsConfigurationMap -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ResetResult(BaseModel): """ @@ -38,11 +34,11 @@ class ResetResult(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["result", "password", "osConfiguration"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +51,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ResetResult from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,11 +66,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of os_configuration @@ -88,7 +86,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ResetResult from a dict""" if obj is None: return None @@ -99,7 +97,7 @@ def from_dict(cls, obj: Dict) -> Self: _obj = cls.model_validate({ "result": obj.get("result"), "password": obj.get("password"), - "osConfiguration": OsConfigurationMap.from_dict(obj.get("osConfiguration")) if obj.get("osConfiguration") is not None else None + "osConfiguration": OsConfigurationMap.from_dict(obj["osConfiguration"]) if obj.get("osConfiguration") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/server.py b/pnap_bmc_api/pnap_bmc_api/models/server.py index 6fec7e3e..d622bba8 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server.py @@ -19,19 +19,16 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional, Union -from pydantic import BaseModel, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_bmc_api.models.gpu_configuration import GpuConfiguration from pnap_bmc_api.models.network_configuration import NetworkConfiguration from pnap_bmc_api.models.os_configuration import OsConfiguration from pnap_bmc_api.models.storage_configuration import StorageConfiguration from pnap_bmc_api.models.tag_assignment import TagAssignment -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Server(BaseModel): """ @@ -41,9 +38,9 @@ class Server(BaseModel): status: StrictStr = Field(description="The status of the server. Can have one of the following values: `creating` , `powered-on` , `powered-off` , `rebooting` , `resetting` , `deleting` , `reserved` , `error` or `reinstating`.") hostname: Annotated[str, Field(min_length=1, strict=True, max_length=100)] = Field(description="Hostname of server.") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="Description of server.") - os: Optional[StrictStr] = Field(default=None, description="The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`.") - type: StrictStr = Field(description="Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, s4.x6.c6.large or s4.x6.m6.xlarge.") - location: StrictStr = Field(description="Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`.") + os: Optional[StrictStr] = Field(default=None, description="The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`.") + type: StrictStr = Field(description="Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, `d3.g3.c2.medium`, `s4.x6.c6.large`, `s4.x6.m6.xlarge`, `s5.x6.c3.medium`, `s5.x6.c3.large`, `s5.x6.c8.medium`, `s5.x6.c9.medium`, `s5.x6.c8.large`, `s5.x6.c9.large`, `s5.x6.m8.xlarge`, `s5.x6.m9.xlarge`, `s4.c3.medium`, `s4.c6.medium`, `s4.c6.large`, `s4.c6.xlarge`, `s4.s2.large`, `a2.c9.large` or `a2.c9.xlarge`.") + location: StrictStr = Field(description="Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`.") cpu: StrictStr = Field(description="A description of the machine CPU.") cpu_count: Annotated[int, Field(strict=True, ge=1)] = Field(description="The number of CPUs available in the system.", alias="cpuCount") cores_per_cpu: Annotated[int, Field(strict=True, ge=1)] = Field(description="The number of physical cores present on each CPU.", alias="coresPerCpu") @@ -75,11 +72,11 @@ def hostname_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9().-])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -92,7 +89,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Server from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -107,19 +104,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # override the default output from pydantic by calling `to_dict()` of os_configuration if self.os_configuration: @@ -141,7 +140,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Server from a dict""" if obj is None: return None @@ -170,12 +169,12 @@ def from_dict(cls, obj: Dict) -> Self: "password": obj.get("password"), "networkType": obj.get("networkType") if obj.get("networkType") is not None else 'PUBLIC_AND_PRIVATE', "clusterId": obj.get("clusterId"), - "tags": [TagAssignment.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None, + "tags": [TagAssignment.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None, "provisionedOn": obj.get("provisionedOn"), - "osConfiguration": OsConfiguration.from_dict(obj.get("osConfiguration")) if obj.get("osConfiguration") is not None else None, - "networkConfiguration": NetworkConfiguration.from_dict(obj.get("networkConfiguration")) if obj.get("networkConfiguration") is not None else None, - "storageConfiguration": StorageConfiguration.from_dict(obj.get("storageConfiguration")) if obj.get("storageConfiguration") is not None else None, - "gpuConfiguration": GpuConfiguration.from_dict(obj.get("gpuConfiguration")) if obj.get("gpuConfiguration") is not None else None, + "osConfiguration": OsConfiguration.from_dict(obj["osConfiguration"]) if obj.get("osConfiguration") is not None else None, + "networkConfiguration": NetworkConfiguration.from_dict(obj["networkConfiguration"]) if obj.get("networkConfiguration") is not None else None, + "storageConfiguration": StorageConfiguration.from_dict(obj["storageConfiguration"]) if obj.get("storageConfiguration") is not None else None, + "gpuConfiguration": GpuConfiguration.from_dict(obj["gpuConfiguration"]) if obj.get("gpuConfiguration") is not None else None, "supersededBy": obj.get("supersededBy"), "supersedes": obj.get("supersedes") }) diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_create.py b/pnap_bmc_api/pnap_bmc_api/models/server_create.py index 30fbd448..3fe66aba 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_create.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_create.py @@ -18,19 +18,15 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_bmc_api.models.network_configuration import NetworkConfiguration from pnap_bmc_api.models.os_configuration import OsConfiguration from pnap_bmc_api.models.storage_configuration import StorageConfiguration from pnap_bmc_api.models.tag_assignment_request import TagAssignmentRequest -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerCreate(BaseModel): """ @@ -38,9 +34,9 @@ class ServerCreate(BaseModel): """ # noqa: E501 hostname: Annotated[str, Field(min_length=1, strict=True, max_length=100)] = Field(description="Hostname of server.") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="Description of server.") - os: StrictStr = Field(description="The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`.") - type: StrictStr = Field(description="Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, s4.x6.c6.large or s4.x6.m6.xlarge.") - location: StrictStr = Field(description="Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`.") + os: StrictStr = Field(description="The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`.") + type: StrictStr = Field(description="Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`,`d3.g3.c2.medium`, `s4.x6.c6.large`, `s4.x6.m6.xlarge`, `s5.x6.c3.medium`, `s5.x6.c3.large`, `s5.x6.c8.medium`, `s5.x6.c9.medium`, `s5.x6.c8.large`, `s5.x6.c9.large`, `s5.x6.m8.xlarge`, `s5.x6.m9.xlarge`, `s4.c3.medium`, `s4.c6.medium`, `s4.c6.large`, `s4.c6.xlarge`, `s4.s2.large`, `a2.c9.large` or `a2.c9.xlarge`.") + location: StrictStr = Field(description="Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`.") install_default_ssh_keys: Optional[StrictBool] = Field(default=True, description="Whether or not to install SSH keys marked as default in addition to any SSH keys specified in this request.", alias="installDefaultSshKeys") ssh_keys: Optional[List[StrictStr]] = Field(default=None, description="A list of SSH keys that will be installed on the server.", alias="sshKeys") ssh_key_ids: Optional[List[StrictStr]] = Field(default=None, description="A list of SSH key IDs that will be installed on the server in addition to any SSH keys specified in this request.", alias="sshKeyIds") @@ -61,11 +57,11 @@ def hostname_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9().-])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -78,7 +74,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -93,11 +89,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of os_configuration @@ -106,9 +104,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # override the default output from pydantic by calling `to_dict()` of network_configuration if self.network_configuration: @@ -124,7 +122,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerCreate from a dict""" if obj is None: return None @@ -144,10 +142,10 @@ def from_dict(cls, obj: Dict) -> Self: "reservationId": obj.get("reservationId"), "pricingModel": obj.get("pricingModel") if obj.get("pricingModel") is not None else 'HOURLY', "networkType": obj.get("networkType") if obj.get("networkType") is not None else 'PUBLIC_AND_PRIVATE', - "osConfiguration": OsConfiguration.from_dict(obj.get("osConfiguration")) if obj.get("osConfiguration") is not None else None, - "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None, - "networkConfiguration": NetworkConfiguration.from_dict(obj.get("networkConfiguration")) if obj.get("networkConfiguration") is not None else None, - "storageConfiguration": StorageConfiguration.from_dict(obj.get("storageConfiguration")) if obj.get("storageConfiguration") is not None else None + "osConfiguration": OsConfiguration.from_dict(obj["osConfiguration"]) if obj.get("osConfiguration") is not None else None, + "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None, + "networkConfiguration": NetworkConfiguration.from_dict(obj["networkConfiguration"]) if obj.get("networkConfiguration") is not None else None, + "storageConfiguration": StorageConfiguration.from_dict(obj["storageConfiguration"]) if obj.get("storageConfiguration") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_ip_block.py b/pnap_bmc_api/pnap_bmc_api/models/server_ip_block.py index 57566812..57446610 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_ip_block.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_ip_block.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerIpBlock(BaseModel): """ @@ -36,11 +32,11 @@ class ServerIpBlock(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "vlanId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerIpBlock from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,12 +65,14 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "vlan_id", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "vlan_id", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -85,7 +83,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerIpBlock from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_network_update.py b/pnap_bmc_api/pnap_bmc_api/models/server_network_update.py index 4c0739af..3d4ecdf4 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_network_update.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_network_update.py @@ -18,28 +18,24 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerNetworkUpdate(BaseModel): """ Update network details of bare metal server. """ # noqa: E501 - ips: Optional[List[StrictStr]] = Field(default=None, description="List of IPs to be associated to the server.
Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). IPs must be within the network's range.
Setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
  • Assign IP addresses which are considered as reserved in network.
") + ips: Optional[List[StrictStr]] = Field(default=None, description="List of IPs to be associated to the server.
Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). All IPs must be within the network's range.
Setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
  • Assign IP addresses which are considered as reserved in network.
") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["ips"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +48,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerNetworkUpdate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +63,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -82,7 +80,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerNetworkUpdate from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_patch.py b/pnap_bmc_api/pnap_bmc_api/models/server_patch.py index d1504060..23fa9c8e 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_patch.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_patch.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerPatch(BaseModel): """ @@ -47,11 +43,11 @@ def hostname_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /[a-zA-Z0-9().-]+/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -64,7 +60,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerPatch from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -79,11 +75,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -94,7 +92,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerPatch from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_private_network.py b/pnap_bmc_api/pnap_bmc_api/models/server_private_network.py index 61d42816..959ebb3d 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_private_network.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_private_network.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerPrivateNetwork(BaseModel): """ @@ -34,16 +30,17 @@ class ServerPrivateNetwork(BaseModel): """ # noqa: E501 id: StrictStr = Field(description="The network identifier.") ips: Optional[Annotated[List[StrictStr], Field(max_length=256)]] = Field(default=None, description="IPs to configure/configured on the server.
Valid IP formats are single IPv4 addresses or IPv4 ranges. IPs must be within the network's range. Should be null or empty list if DHCP is true.
If field is undefined and DHCP is false, next available IP in network will be automatically allocated.
If the network contains a membership of type 'storage', the first twelve IPs are already reserved by BMC and not usable.
Setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
  • Assign IP addresses which are considered as reserved in network.
") - dhcp: Optional[StrictBool] = Field(default=False, description="Determines whether DHCP is enabled for this server. Should be false if any IPs are provided. Not supported for Proxmox OS.") + dhcp: Optional[StrictBool] = Field(default=False, description="Determines whether DHCP is enabled for this server.
The following restrictions apply when enabling DHCP:
  • DHCP support is limited to servers configured exclusively with private networks (PRIVATE_ONLY).
  • DHCP value needs to be consistent across all server-configured private networks.
  • The server does not support manual gateway address configuration.
  • Private IP addresses for network cannot be specified.
Note: Not supported on Proxmox OS.") status_description: Optional[StrictStr] = Field(default=None, description="(Read-only) The status of the network.", alias="statusDescription") + vlan_id: Optional[StrictInt] = Field(default=None, description="(Read-only) The VLAN on which this network has been configured within the network switch.", alias="vlanId") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["id", "ips", "dhcp", "statusDescription"] + __properties: ClassVar[List[str]] = ["id", "ips", "dhcp", "statusDescription", "vlanId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -56,7 +53,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerPrivateNetwork from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,14 +67,18 @@ def to_dict(self) -> Dict[str, Any]: were set at model initialization. Other fields with value `None` are ignored. * OpenAPI `readOnly` fields are excluded. + * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "status_description", + "vlan_id", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "status_description", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -88,7 +89,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerPrivateNetwork from a dict""" if obj is None: return None @@ -100,7 +101,8 @@ def from_dict(cls, obj: Dict) -> Self: "id": obj.get("id"), "ips": obj.get("ips"), "dhcp": obj.get("dhcp") if obj.get("dhcp") is not None else False, - "statusDescription": obj.get("statusDescription") + "statusDescription": obj.get("statusDescription"), + "vlanId": obj.get("vlanId") }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_provision.py b/pnap_bmc_api/pnap_bmc_api/models/server_provision.py index 035e5803..fe79b587 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_provision.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_provision.py @@ -18,19 +18,15 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_bmc_api.models.network_configuration import NetworkConfiguration from pnap_bmc_api.models.os_configuration import OsConfiguration from pnap_bmc_api.models.storage_configuration import StorageConfiguration from pnap_bmc_api.models.tag_assignment_request import TagAssignmentRequest -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerProvision(BaseModel): """ @@ -38,7 +34,7 @@ class ServerProvision(BaseModel): """ # noqa: E501 hostname: Annotated[str, Field(min_length=1, strict=True, max_length=100)] = Field(description="Hostname of server.") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="Description of server.") - os: StrictStr = Field(description="The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux8`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`.") + os: StrictStr = Field(description="The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux8`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`,`netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`.") install_default_ssh_keys: Optional[StrictBool] = Field(default=True, description="Whether or not to install SSH keys marked as default in addition to any SSH keys specified in this request.", alias="installDefaultSshKeys") ssh_keys: Optional[List[StrictStr]] = Field(default=None, description="A list of SSH keys that will be installed on the server.", alias="sshKeys") ssh_key_ids: Optional[List[StrictStr]] = Field(default=None, description="A list of SSH key IDs that will be installed on the server in addition to any SSH keys specified in this request.", alias="sshKeyIds") @@ -57,11 +53,11 @@ def hostname_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9().-])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -74,7 +70,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerProvision from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -89,11 +85,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of os_configuration @@ -102,9 +100,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # override the default output from pydantic by calling `to_dict()` of network_configuration if self.network_configuration: @@ -120,7 +118,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerProvision from a dict""" if obj is None: return None @@ -136,10 +134,10 @@ def from_dict(cls, obj: Dict) -> Self: "sshKeys": obj.get("sshKeys"), "sshKeyIds": obj.get("sshKeyIds"), "networkType": obj.get("networkType") if obj.get("networkType") is not None else 'PUBLIC_AND_PRIVATE', - "osConfiguration": OsConfiguration.from_dict(obj.get("osConfiguration")) if obj.get("osConfiguration") is not None else None, - "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None, - "networkConfiguration": NetworkConfiguration.from_dict(obj.get("networkConfiguration")) if obj.get("networkConfiguration") is not None else None, - "storageConfiguration": StorageConfiguration.from_dict(obj.get("storageConfiguration")) if obj.get("storageConfiguration") is not None else None + "osConfiguration": OsConfiguration.from_dict(obj["osConfiguration"]) if obj.get("osConfiguration") is not None else None, + "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None, + "networkConfiguration": NetworkConfiguration.from_dict(obj["networkConfiguration"]) if obj.get("networkConfiguration") is not None else None, + "storageConfiguration": StorageConfiguration.from_dict(obj["storageConfiguration"]) if obj.get("storageConfiguration") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_public_network.py b/pnap_bmc_api/pnap_bmc_api/models/server_public_network.py index ab7249a1..63940a3c 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_public_network.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_public_network.py @@ -18,31 +18,28 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerPublicNetwork(BaseModel): """ Public network details of bare metal server. """ # noqa: E501 id: StrictStr = Field(description="The network identifier.") - ips: Optional[List[StrictStr]] = Field(default=None, description="Configurable/configured IPs on the server.
At least 1 IP address is required. Valid IP format is single IP addresses. All IPs must be within the network's range.
Setting the `computeSlaacIp` field to `true` allows you to provide an empty array of IPs.
Additionally, setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
") + ips: Optional[List[StrictStr]] = Field(default=None, description="Configurable/configured IPs on the server.
At least 1 IP address is required. Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). All IPs must be within the network's range.
Setting the `computeSlaacIp` field to `true` allows you to provide an empty array of IPs.
Additionally, setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
") status_description: Optional[StrictStr] = Field(default=None, description="(Read-only) The status of the assignment to the network.", alias="statusDescription") compute_slaac_ip: Optional[StrictBool] = Field(default=None, description="(Write-only) Requests Stateless Address Autoconfiguration (SLAAC). Applicable for Network which contains IPv6 block(s).", alias="computeSlaacIp") + vlan_id: Optional[StrictInt] = Field(default=None, description="(Read-only) The VLAN on which this network has been configured within the network switch.", alias="vlanId") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["id", "ips", "statusDescription", "computeSlaacIp"] + __properties: ClassVar[List[str]] = ["id", "ips", "statusDescription", "computeSlaacIp", "vlanId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +52,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerPublicNetwork from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,14 +66,18 @@ def to_dict(self) -> Dict[str, Any]: were set at model initialization. Other fields with value `None` are ignored. * OpenAPI `readOnly` fields are excluded. + * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "status_description", + "vlan_id", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "status_description", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +88,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerPublicNetwork from a dict""" if obj is None: return None @@ -99,7 +100,8 @@ def from_dict(cls, obj: Dict) -> Self: "id": obj.get("id"), "ips": obj.get("ips"), "statusDescription": obj.get("statusDescription"), - "computeSlaacIp": obj.get("computeSlaacIp") + "computeSlaacIp": obj.get("computeSlaacIp"), + "vlanId": obj.get("vlanId") }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_reserve.py b/pnap_bmc_api/pnap_bmc_api/models/server_reserve.py index 8597b9c9..00ab705c 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_reserve.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_reserve.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerReserve(BaseModel): """ @@ -35,11 +31,11 @@ class ServerReserve(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["pricingModel"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +48,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerReserve from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +63,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -82,7 +80,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerReserve from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/server_reset.py b/pnap_bmc_api/pnap_bmc_api/models/server_reset.py index f6cca5cc..946524e1 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/server_reset.py +++ b/pnap_bmc_api/pnap_bmc_api/models/server_reset.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field from pnap_bmc_api.models.os_configuration_map import OsConfigurationMap -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ServerReset(BaseModel): """ @@ -39,11 +35,11 @@ class ServerReset(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["installDefaultSshKeys", "sshKeys", "sshKeyIds", "osConfiguration"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -56,7 +52,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ServerReset from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -71,11 +67,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of os_configuration @@ -89,7 +87,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ServerReset from a dict""" if obj is None: return None @@ -101,7 +99,7 @@ def from_dict(cls, obj: Dict) -> Self: "installDefaultSshKeys": obj.get("installDefaultSshKeys") if obj.get("installDefaultSshKeys") is not None else True, "sshKeys": obj.get("sshKeys"), "sshKeyIds": obj.get("sshKeyIds"), - "osConfiguration": OsConfigurationMap.from_dict(obj.get("osConfiguration")) if obj.get("osConfiguration") is not None else None + "osConfiguration": OsConfigurationMap.from_dict(obj["osConfiguration"]) if obj.get("osConfiguration") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/ssh_key.py b/pnap_bmc_api/pnap_bmc_api/models/ssh_key.py index d1be523a..ab7a35d6 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/ssh_key.py +++ b/pnap_bmc_api/pnap_bmc_api/models/ssh_key.py @@ -19,13 +19,10 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class SshKey(BaseModel): """ @@ -41,11 +38,11 @@ class SshKey(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "default", "name", "key", "fingerprint", "createdOn", "lastUpdatedOn"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -58,7 +55,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of SshKey from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -73,11 +70,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -88,7 +87,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of SshKey from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/ssh_key_create.py b/pnap_bmc_api/pnap_bmc_api/models/ssh_key_create.py index 7a2fe3e8..1fe8b9aa 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/ssh_key_create.py +++ b/pnap_bmc_api/pnap_bmc_api/models/ssh_key_create.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictBool, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class SshKeyCreate(BaseModel): """ @@ -52,11 +48,11 @@ def key_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?!\s*$).+/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -69,7 +65,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of SshKeyCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -84,11 +80,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -99,7 +97,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of SshKeyCreate from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/ssh_key_update.py b/pnap_bmc_api/pnap_bmc_api/models/ssh_key_update.py index 9dfdd041..4c64bd5c 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/ssh_key_update.py +++ b/pnap_bmc_api/pnap_bmc_api/models/ssh_key_update.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictBool, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class SshKeyUpdate(BaseModel): """ @@ -44,11 +40,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?!\s*$).+/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -61,7 +57,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of SshKeyUpdate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -76,11 +72,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -91,7 +89,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of SshKeyUpdate from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/storage_configuration.py b/pnap_bmc_api/pnap_bmc_api/models/storage_configuration.py index ee1e166c..406a5440 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/storage_configuration.py +++ b/pnap_bmc_api/pnap_bmc_api/models/storage_configuration.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel -from pydantic import Field from pnap_bmc_api.models.storage_configuration_root_partition import StorageConfigurationRootPartition -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class StorageConfiguration(BaseModel): """ @@ -36,11 +32,11 @@ class StorageConfiguration(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["rootPartition"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of StorageConfiguration from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of root_partition @@ -86,7 +84,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of StorageConfiguration from a dict""" if obj is None: return None @@ -95,7 +93,7 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "rootPartition": StorageConfigurationRootPartition.from_dict(obj.get("rootPartition")) if obj.get("rootPartition") is not None else None + "rootPartition": StorageConfigurationRootPartition.from_dict(obj["rootPartition"]) if obj.get("rootPartition") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_bmc_api/pnap_bmc_api/models/storage_configuration_root_partition.py b/pnap_bmc_api/pnap_bmc_api/models/storage_configuration_root_partition.py index a47102df..1f36365c 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/storage_configuration_root_partition.py +++ b/pnap_bmc_api/pnap_bmc_api/models/storage_configuration_root_partition.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class StorageConfigurationRootPartition(BaseModel): """ @@ -36,11 +32,11 @@ class StorageConfigurationRootPartition(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["raid", "size"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of StorageConfigurationRootPartition from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of StorageConfigurationRootPartition from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/tag_assignment.py b/pnap_bmc_api/pnap_bmc_api/models/tag_assignment.py index f667bf19..bf69f46a 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/tag_assignment.py +++ b/pnap_bmc_api/pnap_bmc_api/models/tag_assignment.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagAssignment(BaseModel): """ @@ -45,15 +41,15 @@ def created_by_validate_enum(cls, value): if value is None: return value - if value not in ('USER', 'SYSTEM'): + if value not in set(['USER', 'SYSTEM']): raise ValueError("must be one of enum values ('USER', 'SYSTEM')") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +62,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagAssignment from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -81,11 +77,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -96,7 +94,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagAssignment from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/models/tag_assignment_request.py b/pnap_bmc_api/pnap_bmc_api/models/tag_assignment_request.py index 63d85b02..35e9d1d6 100644 --- a/pnap_bmc_api/pnap_bmc_api/models/tag_assignment_request.py +++ b/pnap_bmc_api/pnap_bmc_api/models/tag_assignment_request.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagAssignmentRequest(BaseModel): """ @@ -36,11 +32,11 @@ class TagAssignmentRequest(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["name", "value"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagAssignmentRequest from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagAssignmentRequest from a dict""" if obj is None: return None diff --git a/pnap_bmc_api/pnap_bmc_api/rest.py b/pnap_bmc_api/pnap_bmc_api/rest.py index d6f3617c..55507e27 100644 --- a/pnap_bmc_api/pnap_bmc_api/rest.py +++ b/pnap_bmc_api/pnap_bmc_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_bmc_api/pnap_bmc_api/version.py b/pnap_bmc_api/pnap_bmc_api/version.py index d5cf5185..7e8ebebd 100644 --- a/pnap_bmc_api/pnap_bmc_api/version.py +++ b/pnap_bmc_api/pnap_bmc_api/version.py @@ -1 +1 @@ -VERSION = "2.2.1" \ No newline at end of file +VERSION = "2.3.0" \ No newline at end of file diff --git a/pnap_bmc_api/pyproject.toml b/pnap_bmc_api/pyproject.toml index f73fc632..2021c84c 100644 --- a/pnap_bmc_api/pyproject.toml +++ b/pnap_bmc_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_bmc_api" -version = "2.2.1" +version = "2.3.0" description = "Bare Metal Cloud API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Bare Metal Cloud API"] -include = ["pnap_bmc_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_bmc_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_bmc_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_bmc_api/requirements.txt b/pnap_bmc_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_bmc_api/requirements.txt +++ b/pnap_bmc_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_bmc_api/setup.py b/pnap_bmc_api/setup.py index 1c0c90bc..9542fadb 100644 --- a/pnap_bmc_api/setup.py +++ b/pnap_bmc_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Bare Metal Cloud API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_bmc_api" -VERSION = "2.2.1" -PYTHON_REQUIRES = ">=3.7" +VERSION = "2.3.0" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ Create, power off, power on, reset, reboot, or shut down your server with the Bare Metal Cloud API. Deprovision servers, get or edit SSH key details, assign public IPs, assign servers to networks and a lot more. Manage your infrastructure more efficiently using just a few simple API calls.<br> <br> <span class='pnap-api-knowledge-base-link'> Knowledge base articles to help you can be found <a href='https://phoenixnap.com/kb/how-to-deploy-bare-metal-cloud-server' target='_blank'>here</a> </span><br> <br> <b>All URLs are relative to (https://api.phoenixnap.com/bmc/v1/)</b> """, # noqa: E501 package_data={"pnap_bmc_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_invoicing_api/README.md b/pnap_invoicing_api/README.md index e7bef88a..9250bf0f 100644 --- a/pnap_invoicing_api/README.md +++ b/pnap_invoicing_api/README.md @@ -5,13 +5,13 @@ List, fetch and pay invoices with the Invoicing API. This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0 -- Package version: 1.0.4 +- Package version: 1.0.5 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -41,9 +41,16 @@ Then import the package: import pnap_invoicing_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_invoicing_api from pnap_invoicing_api.rest import ApiException from pprint import pprint @@ -72,8 +79,8 @@ with pnap_invoicing_api.ApiClient(configuration) as api_client: sent_on_to = '2022-04-13T00:00:00.000Z' # datetime | Maximum value to filter invoices by sent on date. (optional) limit = 100 # int | The limit of the number of results returned. The number of records returned may be smaller than the limit. (optional) (default to 100) offset = 0 # int | The number of items to skip in the results. (optional) (default to 0) - sort_field = 'sentOn' # str | If a sortField is requested, pagination will be done after sorting. Default sorting is by number. (optional) (default to 'sentOn') - sort_direction = 'DESC' # str | Sort Given Field depending on the desired direction. Default sorting is descending. (optional) (default to 'DESC') + sort_field = sentOn # str | If a sortField is requested, pagination will be done after sorting. Default sorting is by number. (optional) (default to sentOn) + sort_direction = DESC # str | Sort Given Field depending on the desired direction. Default sorting is descending. (optional) (default to DESC) try: # List invoices. @@ -101,6 +108,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -142,4 +150,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_invoicing_api/docs/Error.md b/pnap_invoicing_api/docs/Error.md index 8c7e6367..518c3bc3 100644 --- a/pnap_invoicing_api/docs/Error.md +++ b/pnap_invoicing_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_invoicing_api/docs/Invoice.md b/pnap_invoicing_api/docs/Invoice.md index 1656831b..7383d50f 100644 --- a/pnap_invoicing_api/docs/Invoice.md +++ b/pnap_invoicing_api/docs/Invoice.md @@ -24,12 +24,12 @@ json = "{}" # create an instance of Invoice from a JSON string invoice_instance = Invoice.from_json(json) # print the JSON string representation of the object -print Invoice.to_json() +print(Invoice.to_json()) # convert the object into a dict invoice_dict = invoice_instance.to_dict() # create an instance of Invoice from a dict -invoice_form_dict = invoice.from_dict(invoice_dict) +invoice_from_dict = Invoice.from_dict(invoice_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_invoicing_api/docs/InvoicesApi.md b/pnap_invoicing_api/docs/InvoicesApi.md index 3322d572..b2c482ba 100644 --- a/pnap_invoicing_api/docs/InvoicesApi.md +++ b/pnap_invoicing_api/docs/InvoicesApi.md @@ -22,8 +22,6 @@ List invoices. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_invoicing_api from pnap_invoicing_api.models.paginated_invoices import PaginatedInvoices from pnap_invoicing_api.rest import ApiException @@ -52,8 +50,8 @@ with pnap_invoicing_api.ApiClient(configuration) as api_client: sent_on_to = '2022-04-13T00:00:00.000Z' # datetime | Maximum value to filter invoices by sent on date. (optional) limit = 100 # int | The limit of the number of results returned. The number of records returned may be smaller than the limit. (optional) (default to 100) offset = 0 # int | The number of items to skip in the results. (optional) (default to 0) - sort_field = 'sentOn' # str | If a sortField is requested, pagination will be done after sorting. Default sorting is by number. (optional) (default to 'sentOn') - sort_direction = 'DESC' # str | Sort Given Field depending on the desired direction. Default sorting is descending. (optional) (default to 'DESC') + sort_field = sentOn # str | If a sortField is requested, pagination will be done after sorting. Default sorting is by number. (optional) (default to sentOn) + sort_direction = DESC # str | Sort Given Field depending on the desired direction. Default sorting is descending. (optional) (default to DESC) try: # List invoices. @@ -77,8 +75,8 @@ Name | Type | Description | Notes **sent_on_to** | **datetime**| Maximum value to filter invoices by sent on date. | [optional] **limit** | **int**| The limit of the number of results returned. The number of records returned may be smaller than the limit. | [optional] [default to 100] **offset** | **int**| The number of items to skip in the results. | [optional] [default to 0] - **sort_field** | **str**| If a sortField is requested, pagination will be done after sorting. Default sorting is by number. | [optional] [default to 'sentOn'] - **sort_direction** | **str**| Sort Given Field depending on the desired direction. Default sorting is descending. | [optional] [default to 'DESC'] + **sort_field** | **str**| If a sortField is requested, pagination will be done after sorting. Default sorting is by number. | [optional] [default to sentOn] + **sort_direction** | **str**| Sort Given Field depending on the desired direction. Default sorting is descending. | [optional] [default to DESC] ### Return type @@ -117,8 +115,6 @@ Generate invoice details as PDF. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_invoicing_api from pnap_invoicing_api.rest import ApiException from pprint import pprint @@ -196,8 +192,6 @@ Get invoice details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_invoicing_api from pnap_invoicing_api.models.invoice import Invoice from pnap_invoicing_api.rest import ApiException @@ -276,8 +270,6 @@ Manually pay an invoice. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_invoicing_api from pnap_invoicing_api.rest import ApiException from pprint import pprint diff --git a/pnap_invoicing_api/docs/PaginatedInvoices.md b/pnap_invoicing_api/docs/PaginatedInvoices.md index 576f0e9d..ec56350e 100644 --- a/pnap_invoicing_api/docs/PaginatedInvoices.md +++ b/pnap_invoicing_api/docs/PaginatedInvoices.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of PaginatedInvoices from a JSON string paginated_invoices_instance = PaginatedInvoices.from_json(json) # print the JSON string representation of the object -print PaginatedInvoices.to_json() +print(PaginatedInvoices.to_json()) # convert the object into a dict paginated_invoices_dict = paginated_invoices_instance.to_dict() # create an instance of PaginatedInvoices from a dict -paginated_invoices_form_dict = paginated_invoices.from_dict(paginated_invoices_dict) +paginated_invoices_from_dict = PaginatedInvoices.from_dict(paginated_invoices_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_invoicing_api/docs/PaginatedResponse.md b/pnap_invoicing_api/docs/PaginatedResponse.md index 45ecde92..652badbd 100644 --- a/pnap_invoicing_api/docs/PaginatedResponse.md +++ b/pnap_invoicing_api/docs/PaginatedResponse.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of PaginatedResponse from a JSON string paginated_response_instance = PaginatedResponse.from_json(json) # print the JSON string representation of the object -print PaginatedResponse.to_json() +print(PaginatedResponse.to_json()) # convert the object into a dict paginated_response_dict = paginated_response_instance.to_dict() # create an instance of PaginatedResponse from a dict -paginated_response_form_dict = paginated_response.from_dict(paginated_response_dict) +paginated_response_from_dict = PaginatedResponse.from_dict(paginated_response_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_invoicing_api/pnap_invoicing_api/__init__.py b/pnap_invoicing_api/pnap_invoicing_api/__init__.py index 74b95a0b..199a20d3 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/__init__.py +++ b/pnap_invoicing_api/pnap_invoicing_api/__init__.py @@ -15,24 +15,43 @@ """ # noqa: E501 -__version__ = "1.0.4" +__version__ = "1.0.5" + +# Define package exports +__all__ = [ + "InvoicesApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "Error", + "Invoice", + "PaginatedInvoices", + "PaginatedResponse", +] # import apis into sdk package -from pnap_invoicing_api.api.invoices_api import InvoicesApi +from pnap_invoicing_api.api.invoices_api import InvoicesApi as InvoicesApi # import ApiClient -from pnap_invoicing_api.api_response import ApiResponse -from pnap_invoicing_api.api_client import ApiClient -from pnap_invoicing_api.configuration import Configuration -from pnap_invoicing_api.exceptions import OpenApiException -from pnap_invoicing_api.exceptions import ApiTypeError -from pnap_invoicing_api.exceptions import ApiValueError -from pnap_invoicing_api.exceptions import ApiKeyError -from pnap_invoicing_api.exceptions import ApiAttributeError -from pnap_invoicing_api.exceptions import ApiException +from pnap_invoicing_api.api_response import ApiResponse as ApiResponse +from pnap_invoicing_api.api_client import ApiClient as ApiClient +from pnap_invoicing_api.configuration import Configuration as Configuration +from pnap_invoicing_api.exceptions import OpenApiException as OpenApiException +from pnap_invoicing_api.exceptions import ApiTypeError as ApiTypeError +from pnap_invoicing_api.exceptions import ApiValueError as ApiValueError +from pnap_invoicing_api.exceptions import ApiKeyError as ApiKeyError +from pnap_invoicing_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_invoicing_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_invoicing_api.models.error import Error -from pnap_invoicing_api.models.invoice import Invoice -from pnap_invoicing_api.models.paginated_invoices import PaginatedInvoices -from pnap_invoicing_api.models.paginated_response import PaginatedResponse +from pnap_invoicing_api.models.error import Error as Error +from pnap_invoicing_api.models.invoice import Invoice as Invoice +from pnap_invoicing_api.models.paginated_invoices import PaginatedInvoices as PaginatedInvoices +from pnap_invoicing_api.models.paginated_response import PaginatedResponse as PaginatedResponse + diff --git a/pnap_invoicing_api/pnap_invoicing_api/api/invoices_api.py b/pnap_invoicing_api/pnap_invoicing_api/api/invoices_api.py index 3df03c85..81ca4b6c 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/api/invoices_api.py +++ b/pnap_invoicing_api/pnap_invoicing_api/api/invoices_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Invoicing API @@ -13,29 +11,19 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from datetime import datetime - -from pydantic import StrictStr, field_validator - -from typing import Any, Dict, Optional, Union +from datetime import datetime +from pydantic import Field, StrictBytes, StrictStr, field_validator +from typing import Any, Dict, Optional, Tuple, Union +from typing_extensions import Annotated from pnap_invoicing_api.models.invoice import Invoice from pnap_invoicing_api.models.paginated_invoices import PaginatedInvoices -from pnap_invoicing_api.api_client import ApiClient +from pnap_invoicing_api.api_client import ApiClient, RequestSerialized from pnap_invoicing_api.api_response import ApiResponse from pnap_invoicing_api.rest import RESTResponseType @@ -360,7 +348,7 @@ def _invoices_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -371,7 +359,9 @@ def _invoices_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -432,11 +422,12 @@ def _invoices_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -675,7 +666,7 @@ def _invoices_invoice_id_generate_pdf_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -686,7 +677,9 @@ def _invoices_invoice_id_generate_pdf_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -699,12 +692,13 @@ def _invoices_invoice_id_generate_pdf_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/pdf', - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/pdf', + 'application/json' + ] + ) # authentication setting @@ -943,7 +937,7 @@ def _invoices_invoice_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -954,7 +948,9 @@ def _invoices_invoice_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -967,11 +963,12 @@ def _invoices_invoice_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1226,7 +1223,7 @@ def _invoices_invoice_id_pay_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1237,7 +1234,9 @@ def _invoices_invoice_id_pay_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1252,11 +1251,12 @@ def _invoices_invoice_id_pay_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_invoicing_api/pnap_invoicing_api/api_client.py b/pnap_invoicing_api/pnap_invoicing_api/api_client.py index 999d6f16..d2d1c42d 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/api_client.py +++ b/pnap_invoicing_api/pnap_invoicing_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Invoicing API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_invoicing_api.configuration import Configuration -from pnap_invoicing_api.api_response import ApiResponse +from pnap_invoicing_api.api_response import ApiResponse, T as ApiResponseT import pnap_invoicing_api.models from pnap_invoicing_api import rest from pnap_invoicing_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_invoicing_api/1.0.4" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_invoicing_api/1.0.5" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_invoicing_api/1.0.4" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_invoicing_api/1.0.5" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_invoicing_api/pnap_invoicing_api/api_response.py b/pnap_invoicing_api/pnap_invoicing_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/api_response.py +++ b/pnap_invoicing_api/pnap_invoicing_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_invoicing_api/pnap_invoicing_api/configuration.py b/pnap_invoicing_api/pnap_invoicing_api/configuration.py index f61cb5c5..63a2217a 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/configuration.py +++ b/pnap_invoicing_api/pnap_invoicing_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Invoicing API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/invoicing/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0\n"\ - "SDK Package Version: 1.0.4".\ + "SDK Package Version: 1.0.5".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_invoicing_api/pnap_invoicing_api/exceptions.py b/pnap_invoicing_api/pnap_invoicing_api/exceptions.py index bd11ae71..e8b5f418 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/exceptions.py +++ b/pnap_invoicing_api/pnap_invoicing_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Invoicing API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_invoicing_api/pnap_invoicing_api/models/__init__.py b/pnap_invoicing_api/pnap_invoicing_api/models/__init__.py index 3b32adec..4a1f6a08 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/models/__init__.py +++ b/pnap_invoicing_api/pnap_invoicing_api/models/__init__.py @@ -13,9 +13,9 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_invoicing_api.models.error import Error from pnap_invoicing_api.models.invoice import Invoice from pnap_invoicing_api.models.paginated_invoices import PaginatedInvoices from pnap_invoicing_api.models.paginated_response import PaginatedResponse + diff --git a/pnap_invoicing_api/pnap_invoicing_api/models/error.py b/pnap_invoicing_api/pnap_invoicing_api/models/error.py index 309837b4..fb96ebea 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/models/error.py +++ b/pnap_invoicing_api/pnap_invoicing_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_invoicing_api/pnap_invoicing_api/models/invoice.py b/pnap_invoicing_api/pnap_invoicing_api/models/invoice.py index 3f4fb595..506430d7 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/models/invoice.py +++ b/pnap_invoicing_api/pnap_invoicing_api/models/invoice.py @@ -19,13 +19,10 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Union -from pydantic import BaseModel, StrictFloat, StrictInt, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Invoice(BaseModel): """ @@ -42,11 +39,11 @@ class Invoice(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "number", "currency", "amount", "outstandingAmount", "status", "sentOn", "dueDate"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -59,7 +56,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Invoice from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -74,11 +71,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -89,7 +88,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Invoice from a dict""" if obj is None: return None diff --git a/pnap_invoicing_api/pnap_invoicing_api/models/paginated_invoices.py b/pnap_invoicing_api/pnap_invoicing_api/models/paginated_invoices.py index e957abc2..4b2ee1a6 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/models/paginated_invoices.py +++ b/pnap_invoicing_api/pnap_invoicing_api/models/paginated_invoices.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictInt -from pydantic import Field from pnap_invoicing_api.models.invoice import Invoice -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PaginatedInvoices(BaseModel): """ @@ -39,11 +35,11 @@ class PaginatedInvoices(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["limit", "offset", "total", "results"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -56,7 +52,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PaginatedInvoices from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -71,19 +67,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in results (list) _items = [] if self.results: - for _item in self.results: - if _item: - _items.append(_item.to_dict()) + for _item_results in self.results: + if _item_results: + _items.append(_item_results.to_dict()) _dict['results'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -93,7 +91,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PaginatedInvoices from a dict""" if obj is None: return None @@ -105,7 +103,7 @@ def from_dict(cls, obj: Dict) -> Self: "limit": obj.get("limit"), "offset": obj.get("offset"), "total": obj.get("total"), - "results": [Invoice.from_dict(_item) for _item in obj.get("results")] if obj.get("results") is not None else None + "results": [Invoice.from_dict(_item) for _item in obj["results"]] if obj.get("results") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_invoicing_api/pnap_invoicing_api/models/paginated_response.py b/pnap_invoicing_api/pnap_invoicing_api/models/paginated_response.py index b6d3d562..601f68e2 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/models/paginated_response.py +++ b/pnap_invoicing_api/pnap_invoicing_api/models/paginated_response.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictInt -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PaginatedResponse(BaseModel): """ @@ -37,11 +33,11 @@ class PaginatedResponse(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["limit", "offset", "total"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PaginatedResponse from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PaginatedResponse from a dict""" if obj is None: return None diff --git a/pnap_invoicing_api/pnap_invoicing_api/rest.py b/pnap_invoicing_api/pnap_invoicing_api/rest.py index 580c0104..6242f66e 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/rest.py +++ b/pnap_invoicing_api/pnap_invoicing_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_invoicing_api/pnap_invoicing_api/version.py b/pnap_invoicing_api/pnap_invoicing_api/version.py index dc4e9f63..92f6d2de 100644 --- a/pnap_invoicing_api/pnap_invoicing_api/version.py +++ b/pnap_invoicing_api/pnap_invoicing_api/version.py @@ -1 +1 @@ -VERSION = "1.0.4" \ No newline at end of file +VERSION = "1.0.5" \ No newline at end of file diff --git a/pnap_invoicing_api/pyproject.toml b/pnap_invoicing_api/pyproject.toml index f0efdaa4..47a02f81 100644 --- a/pnap_invoicing_api/pyproject.toml +++ b/pnap_invoicing_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_invoicing_api" -version = "1.0.4" +version = "1.0.5" description = "Invoicing API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Invoicing API"] -include = ["pnap_invoicing_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_invoicing_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_invoicing_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_invoicing_api/requirements.txt b/pnap_invoicing_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_invoicing_api/requirements.txt +++ b/pnap_invoicing_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_invoicing_api/setup.py b/pnap_invoicing_api/setup.py index afddd1dc..451ef6e5 100644 --- a/pnap_invoicing_api/setup.py +++ b/pnap_invoicing_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Invoicing API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_invoicing_api" -VERSION = "1.0.4" -PYTHON_REQUIRES = ">=3.7" +VERSION = "1.0.5" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ List, fetch and pay invoices with the Invoicing API. """, # noqa: E501 package_data={"pnap_invoicing_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_ip_api/README.md b/pnap_ip_api/README.md index 915f3622..2ba4f5ad 100644 --- a/pnap_ip_api/README.md +++ b/pnap_ip_api/README.md @@ -13,13 +13,13 @@ Knowledge base articles to help you can be found This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0 -- Package version: 2.1.1 +- Package version: 2.2.0 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -49,9 +49,16 @@ Then import the package: import pnap_ip_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_ip_api from pnap_ip_api.rest import ApiException from pprint import pprint @@ -102,6 +109,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -148,4 +156,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_ip_api/docs/DeleteIpBlockResult.md b/pnap_ip_api/docs/DeleteIpBlockResult.md index 9ab970a1..5c0467f7 100644 --- a/pnap_ip_api/docs/DeleteIpBlockResult.md +++ b/pnap_ip_api/docs/DeleteIpBlockResult.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of DeleteIpBlockResult from a JSON string delete_ip_block_result_instance = DeleteIpBlockResult.from_json(json) # print the JSON string representation of the object -print DeleteIpBlockResult.to_json() +print(DeleteIpBlockResult.to_json()) # convert the object into a dict delete_ip_block_result_dict = delete_ip_block_result_instance.to_dict() # create an instance of DeleteIpBlockResult from a dict -delete_ip_block_result_form_dict = delete_ip_block_result.from_dict(delete_ip_block_result_dict) +delete_ip_block_result_from_dict = DeleteIpBlockResult.from_dict(delete_ip_block_result_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_ip_api/docs/Error.md b/pnap_ip_api/docs/Error.md index 95d44bb8..d25604a1 100644 --- a/pnap_ip_api/docs/Error.md +++ b/pnap_ip_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_ip_api/docs/IPBlocksApi.md b/pnap_ip_api/docs/IPBlocksApi.md index 2ffc3ec9..7cd13027 100644 --- a/pnap_ip_api/docs/IPBlocksApi.md +++ b/pnap_ip_api/docs/IPBlocksApi.md @@ -24,8 +24,6 @@ List all IP Blocks. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_ip_api from pnap_ip_api.models.ip_block import IpBlock from pnap_ip_api.rest import ApiException @@ -104,8 +102,6 @@ Delete an IP Block. An IP Block can only be deleted if not assigned to any resou * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_ip_api from pnap_ip_api.models.delete_ip_block_result import DeleteIpBlockResult from pnap_ip_api.rest import ApiException @@ -184,8 +180,6 @@ Get IP Block. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_ip_api from pnap_ip_api.models.ip_block import IpBlock from pnap_ip_api.rest import ApiException @@ -264,8 +258,6 @@ Update IP Block's details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_ip_api from pnap_ip_api.models.ip_block import IpBlock from pnap_ip_api.models.ip_block_patch import IpBlockPatch @@ -349,8 +341,6 @@ Overwrites tags assigned for IP Block and unassigns any tags not part of the req * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_ip_api from pnap_ip_api.models.ip_block import IpBlock from pnap_ip_api.models.tag_assignment_request import TagAssignmentRequest @@ -433,8 +423,6 @@ Request an IP Block. An IP Block is a set of contiguous IPs that can be assigned * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_ip_api from pnap_ip_api.models.ip_block import IpBlock from pnap_ip_api.models.ip_block_create import IpBlockCreate diff --git a/pnap_ip_api/docs/IpBlock.md b/pnap_ip_api/docs/IpBlock.md index 82c87e16..af85724d 100644 --- a/pnap_ip_api/docs/IpBlock.md +++ b/pnap_ip_api/docs/IpBlock.md @@ -7,15 +7,17 @@ IP Block Details. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **str** | IP Block identifier. | [optional] -**location** | **str** | IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. | [optional] +**location** | **str** | IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. | [optional] **cidr_block_size** | **str** | CIDR IP Block Size. Currently this field should be set to either `/31`, `/30`, `/29`, `/28`, `/27`, `/26`, `/25`, `/24`, `/23` or `/22`. | [optional] **cidr** | **str** | The IP Block in CIDR notation. | [optional] **ip_version** | **str** | The IP Version of the block. | [optional] -**status** | **str** | The status of the IP Block. Can have one of the following values: `creating` , `assigning` , `error assigning` , `assigned` , `unassigning` , `error unassigning` or `unassigned`. | [optional] +**status** | **str** | The status of the IP Block. Can have one of the following values: `creating`, `subnetted`, `assigning` , `error assigning` , `assigned` , `unassigning` , `error unassigning` or `unassigned`. | [optional] +**parent_ip_block_allocation_id** | **str** | IP Block parent identifier. If present, this block is subnetted from the parent IP Block. | [optional] **assigned_resource_id** | **str** | ID of the resource assigned to the IP Block. | [optional] **assigned_resource_type** | **str** | Type of the resource assigned to the IP Block. | [optional] **description** | **str** | The description of the IP Block. | [optional] **tags** | [**List[TagAssignment]**](TagAssignment.md) | The tags assigned if any. | [optional] +**is_system_managed** | **bool** | True if the IP block is a `system managed` block. | [optional] **is_bring_your_own** | **bool** | True if the IP block is a `bring your own` block. | [optional] **created_on** | **datetime** | Date and time when the IP block was created. | [optional] @@ -29,12 +31,12 @@ json = "{}" # create an instance of IpBlock from a JSON string ip_block_instance = IpBlock.from_json(json) # print the JSON string representation of the object -print IpBlock.to_json() +print(IpBlock.to_json()) # convert the object into a dict ip_block_dict = ip_block_instance.to_dict() # create an instance of IpBlock from a dict -ip_block_form_dict = ip_block.from_dict(ip_block_dict) +ip_block_from_dict = IpBlock.from_dict(ip_block_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_ip_api/docs/IpBlockCreate.md b/pnap_ip_api/docs/IpBlockCreate.md index 1b8a004d..83efef8b 100644 --- a/pnap_ip_api/docs/IpBlockCreate.md +++ b/pnap_ip_api/docs/IpBlockCreate.md @@ -6,7 +6,7 @@ IP Block Request. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**location** | **str** | IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. | +**location** | **str** | IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. | **cidr_block_size** | **str** | CIDR IP Block Size. V4 supported sizes: [`/31`, `/30`, `/29` or `/28`]. V6 supported sizes: [`/64`]. For a larger Block Size contact support. | **ip_version** | **str** | IP Version. This field should be set to `V4` or `V6` | [optional] [default to 'V4'] **description** | **str** | The description of the IP Block. | [optional] @@ -22,12 +22,12 @@ json = "{}" # create an instance of IpBlockCreate from a JSON string ip_block_create_instance = IpBlockCreate.from_json(json) # print the JSON string representation of the object -print IpBlockCreate.to_json() +print(IpBlockCreate.to_json()) # convert the object into a dict ip_block_create_dict = ip_block_create_instance.to_dict() # create an instance of IpBlockCreate from a dict -ip_block_create_form_dict = ip_block_create.from_dict(ip_block_create_dict) +ip_block_create_from_dict = IpBlockCreate.from_dict(ip_block_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_ip_api/docs/IpBlockPatch.md b/pnap_ip_api/docs/IpBlockPatch.md index b34f1fb8..29a81a9b 100644 --- a/pnap_ip_api/docs/IpBlockPatch.md +++ b/pnap_ip_api/docs/IpBlockPatch.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of IpBlockPatch from a JSON string ip_block_patch_instance = IpBlockPatch.from_json(json) # print the JSON string representation of the object -print IpBlockPatch.to_json() +print(IpBlockPatch.to_json()) # convert the object into a dict ip_block_patch_dict = ip_block_patch_instance.to_dict() # create an instance of IpBlockPatch from a dict -ip_block_patch_form_dict = ip_block_patch.from_dict(ip_block_patch_dict) +ip_block_patch_from_dict = IpBlockPatch.from_dict(ip_block_patch_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_ip_api/docs/TagAssignment.md b/pnap_ip_api/docs/TagAssignment.md index 0af81103..900a44c2 100644 --- a/pnap_ip_api/docs/TagAssignment.md +++ b/pnap_ip_api/docs/TagAssignment.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of TagAssignment from a JSON string tag_assignment_instance = TagAssignment.from_json(json) # print the JSON string representation of the object -print TagAssignment.to_json() +print(TagAssignment.to_json()) # convert the object into a dict tag_assignment_dict = tag_assignment_instance.to_dict() # create an instance of TagAssignment from a dict -tag_assignment_form_dict = tag_assignment.from_dict(tag_assignment_dict) +tag_assignment_from_dict = TagAssignment.from_dict(tag_assignment_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_ip_api/docs/TagAssignmentRequest.md b/pnap_ip_api/docs/TagAssignmentRequest.md index 2f19daf4..04cc91e0 100644 --- a/pnap_ip_api/docs/TagAssignmentRequest.md +++ b/pnap_ip_api/docs/TagAssignmentRequest.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of TagAssignmentRequest from a JSON string tag_assignment_request_instance = TagAssignmentRequest.from_json(json) # print the JSON string representation of the object -print TagAssignmentRequest.to_json() +print(TagAssignmentRequest.to_json()) # convert the object into a dict tag_assignment_request_dict = tag_assignment_request_instance.to_dict() # create an instance of TagAssignmentRequest from a dict -tag_assignment_request_form_dict = tag_assignment_request.from_dict(tag_assignment_request_dict) +tag_assignment_request_from_dict = TagAssignmentRequest.from_dict(tag_assignment_request_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_ip_api/pnap_ip_api/__init__.py b/pnap_ip_api/pnap_ip_api/__init__.py index 5fd3dd91..0e9cbd66 100644 --- a/pnap_ip_api/pnap_ip_api/__init__.py +++ b/pnap_ip_api/pnap_ip_api/__init__.py @@ -15,27 +15,49 @@ """ # noqa: E501 -__version__ = "2.1.1" +__version__ = "2.2.0" + +# Define package exports +__all__ = [ + "IPBlocksApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "DeleteIpBlockResult", + "Error", + "IpBlock", + "IpBlockCreate", + "IpBlockPatch", + "TagAssignment", + "TagAssignmentRequest", +] # import apis into sdk package -from pnap_ip_api.api.ip_blocks_api import IPBlocksApi +from pnap_ip_api.api.ip_blocks_api import IPBlocksApi as IPBlocksApi # import ApiClient -from pnap_ip_api.api_response import ApiResponse -from pnap_ip_api.api_client import ApiClient -from pnap_ip_api.configuration import Configuration -from pnap_ip_api.exceptions import OpenApiException -from pnap_ip_api.exceptions import ApiTypeError -from pnap_ip_api.exceptions import ApiValueError -from pnap_ip_api.exceptions import ApiKeyError -from pnap_ip_api.exceptions import ApiAttributeError -from pnap_ip_api.exceptions import ApiException +from pnap_ip_api.api_response import ApiResponse as ApiResponse +from pnap_ip_api.api_client import ApiClient as ApiClient +from pnap_ip_api.configuration import Configuration as Configuration +from pnap_ip_api.exceptions import OpenApiException as OpenApiException +from pnap_ip_api.exceptions import ApiTypeError as ApiTypeError +from pnap_ip_api.exceptions import ApiValueError as ApiValueError +from pnap_ip_api.exceptions import ApiKeyError as ApiKeyError +from pnap_ip_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_ip_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_ip_api.models.delete_ip_block_result import DeleteIpBlockResult -from pnap_ip_api.models.error import Error -from pnap_ip_api.models.ip_block import IpBlock -from pnap_ip_api.models.ip_block_create import IpBlockCreate -from pnap_ip_api.models.ip_block_patch import IpBlockPatch -from pnap_ip_api.models.tag_assignment import TagAssignment -from pnap_ip_api.models.tag_assignment_request import TagAssignmentRequest +from pnap_ip_api.models.delete_ip_block_result import DeleteIpBlockResult as DeleteIpBlockResult +from pnap_ip_api.models.error import Error as Error +from pnap_ip_api.models.ip_block import IpBlock as IpBlock +from pnap_ip_api.models.ip_block_create import IpBlockCreate as IpBlockCreate +from pnap_ip_api.models.ip_block_patch import IpBlockPatch as IpBlockPatch +from pnap_ip_api.models.tag_assignment import TagAssignment as TagAssignment +from pnap_ip_api.models.tag_assignment_request import TagAssignmentRequest as TagAssignmentRequest + diff --git a/pnap_ip_api/pnap_ip_api/api/ip_blocks_api.py b/pnap_ip_api/pnap_ip_api/api/ip_blocks_api.py index 2d76caa4..a23a0789 100644 --- a/pnap_ip_api/pnap_ip_api/api/ip_blocks_api.py +++ b/pnap_ip_api/pnap_ip_api/api/ip_blocks_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ IP Addresses API @@ -13,30 +11,21 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictStr +from pydantic import Field, StrictStr from typing import List, Optional - +from typing_extensions import Annotated from pnap_ip_api.models.delete_ip_block_result import DeleteIpBlockResult from pnap_ip_api.models.ip_block import IpBlock from pnap_ip_api.models.ip_block_create import IpBlockCreate from pnap_ip_api.models.ip_block_patch import IpBlockPatch from pnap_ip_api.models.tag_assignment_request import TagAssignmentRequest -from pnap_ip_api.api_client import ApiClient +from pnap_ip_api.api_client import ApiClient, RequestSerialized from pnap_ip_api.api_response import ApiResponse from pnap_ip_api.rest import RESTResponseType @@ -267,7 +256,7 @@ def _ip_blocks_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -279,7 +268,9 @@ def _ip_blocks_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -294,11 +285,12 @@ def _ip_blocks_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -537,7 +529,7 @@ def _ip_blocks_ip_block_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -548,7 +540,9 @@ def _ip_blocks_ip_block_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -561,11 +555,12 @@ def _ip_blocks_ip_block_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -804,7 +799,7 @@ def _ip_blocks_ip_block_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -815,7 +810,9 @@ def _ip_blocks_ip_block_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -828,11 +825,12 @@ def _ip_blocks_ip_block_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1090,7 +1088,7 @@ def _ip_blocks_ip_block_id_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1101,7 +1099,9 @@ def _ip_blocks_ip_block_id_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1116,11 +1116,12 @@ def _ip_blocks_ip_block_id_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1388,7 +1389,7 @@ def _ip_blocks_ip_block_id_tags_put_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1400,7 +1401,9 @@ def _ip_blocks_ip_block_id_tags_put_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1415,11 +1418,12 @@ def _ip_blocks_ip_block_id_tags_put_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1677,7 +1681,7 @@ def _ip_blocks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1688,7 +1692,9 @@ def _ip_blocks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1701,11 +1707,12 @@ def _ip_blocks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_ip_api/pnap_ip_api/api_client.py b/pnap_ip_api/pnap_ip_api/api_client.py index dfdbd8b1..49192d0f 100644 --- a/pnap_ip_api/pnap_ip_api/api_client.py +++ b/pnap_ip_api/pnap_ip_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ IP Addresses API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_ip_api.configuration import Configuration -from pnap_ip_api.api_response import ApiResponse +from pnap_ip_api.api_response import ApiResponse, T as ApiResponseT import pnap_ip_api.models from pnap_ip_api import rest from pnap_ip_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_ip_api/2.1.1" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_ip_api/2.2.0" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_ip_api/2.1.1" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_ip_api/2.2.0" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_ip_api/pnap_ip_api/api_response.py b/pnap_ip_api/pnap_ip_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_ip_api/pnap_ip_api/api_response.py +++ b/pnap_ip_api/pnap_ip_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_ip_api/pnap_ip_api/configuration.py b/pnap_ip_api/pnap_ip_api/configuration.py index 44efe778..6c7d2a36 100644 --- a/pnap_ip_api/pnap_ip_api/configuration.py +++ b/pnap_ip_api/pnap_ip_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ IP Addresses API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/ips/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0\n"\ - "SDK Package Version: 2.1.1".\ + "SDK Package Version: 2.2.0".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_ip_api/pnap_ip_api/exceptions.py b/pnap_ip_api/pnap_ip_api/exceptions.py index 3ae8c7ab..b0a60ad7 100644 --- a/pnap_ip_api/pnap_ip_api/exceptions.py +++ b/pnap_ip_api/pnap_ip_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ IP Addresses API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_ip_api/pnap_ip_api/models/__init__.py b/pnap_ip_api/pnap_ip_api/models/__init__.py index baee8e86..c8caa7aa 100644 --- a/pnap_ip_api/pnap_ip_api/models/__init__.py +++ b/pnap_ip_api/pnap_ip_api/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_ip_api.models.delete_ip_block_result import DeleteIpBlockResult from pnap_ip_api.models.error import Error @@ -22,3 +21,4 @@ from pnap_ip_api.models.ip_block_patch import IpBlockPatch from pnap_ip_api.models.tag_assignment import TagAssignment from pnap_ip_api.models.tag_assignment_request import TagAssignmentRequest + diff --git a/pnap_ip_api/pnap_ip_api/models/delete_ip_block_result.py b/pnap_ip_api/pnap_ip_api/models/delete_ip_block_result.py index acf87820..c7a33a55 100644 --- a/pnap_ip_api/pnap_ip_api/models/delete_ip_block_result.py +++ b/pnap_ip_api/pnap_ip_api/models/delete_ip_block_result.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class DeleteIpBlockResult(BaseModel): """ @@ -36,11 +32,11 @@ class DeleteIpBlockResult(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["result", "ipBlockId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of DeleteIpBlockResult from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of DeleteIpBlockResult from a dict""" if obj is None: return None diff --git a/pnap_ip_api/pnap_ip_api/models/error.py b/pnap_ip_api/pnap_ip_api/models/error.py index 9dd0b0ec..87a45316 100644 --- a/pnap_ip_api/pnap_ip_api/models/error.py +++ b/pnap_ip_api/pnap_ip_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_ip_api/pnap_ip_api/models/ip_block.py b/pnap_ip_api/pnap_ip_api/models/ip_block.py index 79020786..3597d2cf 100644 --- a/pnap_ip_api/pnap_ip_api/models/ip_block.py +++ b/pnap_ip_api/pnap_ip_api/models/ip_block.py @@ -19,40 +19,39 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field from typing_extensions import Annotated from pnap_ip_api.models.tag_assignment import TagAssignment -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class IpBlock(BaseModel): """ IP Block Details. """ # noqa: E501 id: Optional[StrictStr] = Field(default=None, description="IP Block identifier.") - location: Optional[StrictStr] = Field(default=None, description="IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`.") + location: Optional[StrictStr] = Field(default=None, description="IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`.") cidr_block_size: Optional[StrictStr] = Field(default=None, description="CIDR IP Block Size. Currently this field should be set to either `/31`, `/30`, `/29`, `/28`, `/27`, `/26`, `/25`, `/24`, `/23` or `/22`.", alias="cidrBlockSize") cidr: Optional[StrictStr] = Field(default=None, description="The IP Block in CIDR notation.") ip_version: Optional[StrictStr] = Field(default=None, description="The IP Version of the block.", alias="ipVersion") - status: Optional[StrictStr] = Field(default=None, description="The status of the IP Block. Can have one of the following values: `creating` , `assigning` , `error assigning` , `assigned` , `unassigning` , `error unassigning` or `unassigned`.") + status: Optional[StrictStr] = Field(default=None, description="The status of the IP Block. Can have one of the following values: `creating`, `subnetted`, `assigning` , `error assigning` , `assigned` , `unassigning` , `error unassigning` or `unassigned`.") + parent_ip_block_allocation_id: Optional[StrictStr] = Field(default=None, description="IP Block parent identifier. If present, this block is subnetted from the parent IP Block.", alias="parentIpBlockAllocationId") assigned_resource_id: Optional[StrictStr] = Field(default=None, description="ID of the resource assigned to the IP Block.", alias="assignedResourceId") assigned_resource_type: Optional[StrictStr] = Field(default=None, description="Type of the resource assigned to the IP Block.", alias="assignedResourceType") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="The description of the IP Block.") tags: Optional[List[TagAssignment]] = Field(default=None, description="The tags assigned if any.") + is_system_managed: Optional[StrictBool] = Field(default=None, description="True if the IP block is a `system managed` block.", alias="isSystemManaged") is_bring_your_own: Optional[StrictBool] = Field(default=None, description="True if the IP block is a `bring your own` block.", alias="isBringYourOwn") created_on: Optional[datetime] = Field(default=None, description="Date and time when the IP block was created.", alias="createdOn") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["id", "location", "cidrBlockSize", "cidr", "ipVersion", "status", "assignedResourceId", "assignedResourceType", "description", "tags", "isBringYourOwn", "createdOn"] + __properties: ClassVar[List[str]] = ["id", "location", "cidrBlockSize", "cidr", "ipVersion", "status", "parentIpBlockAllocationId", "assignedResourceId", "assignedResourceType", "description", "tags", "isSystemManaged", "isBringYourOwn", "createdOn"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -65,7 +64,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of IpBlock from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -80,19 +79,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -102,7 +103,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of IpBlock from a dict""" if obj is None: return None @@ -117,10 +118,12 @@ def from_dict(cls, obj: Dict) -> Self: "cidr": obj.get("cidr"), "ipVersion": obj.get("ipVersion"), "status": obj.get("status"), + "parentIpBlockAllocationId": obj.get("parentIpBlockAllocationId"), "assignedResourceId": obj.get("assignedResourceId"), "assignedResourceType": obj.get("assignedResourceType"), "description": obj.get("description"), - "tags": [TagAssignment.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None, + "tags": [TagAssignment.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None, + "isSystemManaged": obj.get("isSystemManaged"), "isBringYourOwn": obj.get("isBringYourOwn"), "createdOn": obj.get("createdOn") }) diff --git a/pnap_ip_api/pnap_ip_api/models/ip_block_create.py b/pnap_ip_api/pnap_ip_api/models/ip_block_create.py index 5d20b69c..6f512ad0 100644 --- a/pnap_ip_api/pnap_ip_api/models/ip_block_create.py +++ b/pnap_ip_api/pnap_ip_api/models/ip_block_create.py @@ -18,22 +18,18 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from typing_extensions import Annotated from pnap_ip_api.models.tag_assignment_request import TagAssignmentRequest -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class IpBlockCreate(BaseModel): """ IP Block Request. """ # noqa: E501 - location: StrictStr = Field(description="IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`.") + location: StrictStr = Field(description="IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`.") cidr_block_size: StrictStr = Field(description="CIDR IP Block Size. V4 supported sizes: [`/31`, `/30`, `/29` or `/28`]. V6 supported sizes: [`/64`]. For a larger Block Size contact support.", alias="cidrBlockSize") ip_version: Optional[StrictStr] = Field(default='V4', description="IP Version. This field should be set to `V4` or `V6`", alias="ipVersion") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="The description of the IP Block.") @@ -41,11 +37,11 @@ class IpBlockCreate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["location", "cidrBlockSize", "ipVersion", "description", "tags"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -58,7 +54,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of IpBlockCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -73,19 +69,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -95,7 +93,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of IpBlockCreate from a dict""" if obj is None: return None @@ -108,7 +106,7 @@ def from_dict(cls, obj: Dict) -> Self: "cidrBlockSize": obj.get("cidrBlockSize"), "ipVersion": obj.get("ipVersion") if obj.get("ipVersion") is not None else 'V4', "description": obj.get("description"), - "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None + "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_ip_api/pnap_ip_api/models/ip_block_patch.py b/pnap_ip_api/pnap_ip_api/models/ip_block_patch.py index a0b1b3d3..fbdf1983 100644 --- a/pnap_ip_api/pnap_ip_api/models/ip_block_patch.py +++ b/pnap_ip_api/pnap_ip_api/models/ip_block_patch.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class IpBlockPatch(BaseModel): """ @@ -36,11 +32,11 @@ class IpBlockPatch(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["description"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of IpBlockPatch from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of IpBlockPatch from a dict""" if obj is None: return None diff --git a/pnap_ip_api/pnap_ip_api/models/tag_assignment.py b/pnap_ip_api/pnap_ip_api/models/tag_assignment.py index aeec019b..2387ae13 100644 --- a/pnap_ip_api/pnap_ip_api/models/tag_assignment.py +++ b/pnap_ip_api/pnap_ip_api/models/tag_assignment.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagAssignment(BaseModel): """ @@ -45,15 +41,15 @@ def created_by_validate_enum(cls, value): if value is None: return value - if value not in ('USER', 'SYSTEM'): + if value not in set(['USER', 'SYSTEM']): raise ValueError("must be one of enum values ('USER', 'SYSTEM')") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +62,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagAssignment from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -81,11 +77,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -96,7 +94,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagAssignment from a dict""" if obj is None: return None diff --git a/pnap_ip_api/pnap_ip_api/models/tag_assignment_request.py b/pnap_ip_api/pnap_ip_api/models/tag_assignment_request.py index 8f81e0ed..48f8e233 100644 --- a/pnap_ip_api/pnap_ip_api/models/tag_assignment_request.py +++ b/pnap_ip_api/pnap_ip_api/models/tag_assignment_request.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagAssignmentRequest(BaseModel): """ @@ -36,11 +32,11 @@ class TagAssignmentRequest(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["name", "value"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagAssignmentRequest from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagAssignmentRequest from a dict""" if obj is None: return None diff --git a/pnap_ip_api/pnap_ip_api/rest.py b/pnap_ip_api/pnap_ip_api/rest.py index 516d5069..6d1666ec 100644 --- a/pnap_ip_api/pnap_ip_api/rest.py +++ b/pnap_ip_api/pnap_ip_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_ip_api/pnap_ip_api/version.py b/pnap_ip_api/pnap_ip_api/version.py index 66f584a6..51380664 100644 --- a/pnap_ip_api/pnap_ip_api/version.py +++ b/pnap_ip_api/pnap_ip_api/version.py @@ -1 +1 @@ -VERSION = "2.1.1" \ No newline at end of file +VERSION = "2.2.0" \ No newline at end of file diff --git a/pnap_ip_api/pyproject.toml b/pnap_ip_api/pyproject.toml index 23e466dc..ca6203c1 100644 --- a/pnap_ip_api/pyproject.toml +++ b/pnap_ip_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_ip_api" -version = "2.1.1" +version = "2.2.0" description = "IP Addresses API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "IP Addresses API"] -include = ["pnap_ip_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_ip_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_ip_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_ip_api/requirements.txt b/pnap_ip_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_ip_api/requirements.txt +++ b/pnap_ip_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_ip_api/setup.py b/pnap_ip_api/setup.py index ded1b822..4c071f19 100644 --- a/pnap_ip_api/setup.py +++ b/pnap_ip_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ IP Addresses API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_ip_api" -VERSION = "2.1.1" -PYTHON_REQUIRES = ">=3.7" +VERSION = "2.2.0" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ Public IP blocks are a set of contiguous IPs that allow you to access your servers or networks from the internet. Use the IP Addresses API to request and delete IP blocks.<br> <br> <span class='pnap-api-knowledge-base-link'> Knowledge base articles to help you can be found <a href='https://phoenixnap.com/kb/public-ip-management#bmc-public-ip-allocations-api' target='_blank'>here</a> </span><br> <br> <b>All URLs are relative to (https://api.phoenixnap.com/ips/v1/)</b> """, # noqa: E501 package_data={"pnap_ip_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_location_api/README.md b/pnap_location_api/README.md index 4cbddcec..2bcb1e49 100644 --- a/pnap_location_api/README.md +++ b/pnap_location_api/README.md @@ -4,13 +4,13 @@ No description provided (generated by Openapi Generator https://github.com/opena This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0 -- Package version: 2.0.4 +- Package version: 3.0.0 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com](https://phoenixnap.com) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -40,9 +40,16 @@ Then import the package: import pnap_location_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_location_api from pnap_location_api.rest import ApiException from pprint import pprint @@ -59,7 +66,7 @@ configuration = pnap_location_api.Configuration( with pnap_location_api.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = pnap_location_api.LocationsApi(api_client) - location = pnap_location_api.LocationEnum() # LocationEnum | Location of interest (optional) + location = pnap_location_api.ProductLocationEnum() # ProductLocationEnum | Location of interest (optional) product_category = pnap_location_api.ProductCategoryEnum() # ProductCategoryEnum | Product category of interest (optional) try: @@ -88,6 +95,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -103,9 +111,9 @@ Class | Method | HTTP request | Description - [Error](docs/Error.md) - [Location](docs/Location.md) - - [LocationEnum](docs/LocationEnum.md) - [ProductCategory](docs/ProductCategory.md) - [ProductCategoryEnum](docs/ProductCategoryEnum.md) + - [ProductLocationEnum](docs/ProductLocationEnum.md) @@ -117,4 +125,3 @@ Endpoints do not require authorization. ## Author support@phoenixnap.com - diff --git a/pnap_location_api/docs/Error.md b/pnap_location_api/docs/Error.md index 1de624e2..806bf2b5 100644 --- a/pnap_location_api/docs/Error.md +++ b/pnap_location_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_location_api/docs/Location.md b/pnap_location_api/docs/Location.md index 1853f779..9bcdf938 100644 --- a/pnap_location_api/docs/Location.md +++ b/pnap_location_api/docs/Location.md @@ -6,7 +6,7 @@ Location resource Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**location** | [**LocationEnum**](LocationEnum.md) | | +**location** | [**ProductLocationEnum**](ProductLocationEnum.md) | | **location_description** | **str** | | [optional] **product_categories** | [**List[ProductCategory]**](ProductCategory.md) | | [optional] @@ -20,12 +20,12 @@ json = "{}" # create an instance of Location from a JSON string location_instance = Location.from_json(json) # print the JSON string representation of the object -print Location.to_json() +print(Location.to_json()) # convert the object into a dict location_dict = location_instance.to_dict() # create an instance of Location from a dict -location_form_dict = location.from_dict(location_dict) +location_from_dict = Location.from_dict(location_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_location_api/docs/LocationEnum.md b/pnap_location_api/docs/LocationEnum.md deleted file mode 100644 index 0e46fb77..00000000 --- a/pnap_location_api/docs/LocationEnum.md +++ /dev/null @@ -1,12 +0,0 @@ -# LocationEnum - -The location code. - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/pnap_location_api/docs/LocationsApi.md b/pnap_location_api/docs/LocationsApi.md index 3fad47a8..307caa9f 100644 --- a/pnap_location_api/docs/LocationsApi.md +++ b/pnap_location_api/docs/LocationsApi.md @@ -18,12 +18,10 @@ Retrieve the locations info. ```python -import time -import os import pnap_location_api from pnap_location_api.models.location import Location -from pnap_location_api.models.location_enum import LocationEnum from pnap_location_api.models.product_category_enum import ProductCategoryEnum +from pnap_location_api.models.product_location_enum import ProductLocationEnum from pnap_location_api.rest import ApiException from pprint import pprint @@ -38,7 +36,7 @@ configuration = pnap_location_api.Configuration( with pnap_location_api.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = pnap_location_api.LocationsApi(api_client) - location = pnap_location_api.LocationEnum() # LocationEnum | Location of interest (optional) + location = pnap_location_api.ProductLocationEnum() # ProductLocationEnum | Location of interest (optional) product_category = pnap_location_api.ProductCategoryEnum() # ProductCategoryEnum | Product category of interest (optional) try: @@ -57,7 +55,7 @@ with pnap_location_api.ApiClient(configuration) as api_client: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **location** | [**LocationEnum**](.md)| Location of interest | [optional] + **location** | [**ProductLocationEnum**](.md)| Location of interest | [optional] **product_category** | [**ProductCategoryEnum**](.md)| Product category of interest | [optional] ### Return type diff --git a/pnap_location_api/docs/ProductCategory.md b/pnap_location_api/docs/ProductCategory.md index 64cfd23b..553debbe 100644 --- a/pnap_location_api/docs/ProductCategory.md +++ b/pnap_location_api/docs/ProductCategory.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of ProductCategory from a JSON string product_category_instance = ProductCategory.from_json(json) # print the JSON string representation of the object -print ProductCategory.to_json() +print(ProductCategory.to_json()) # convert the object into a dict product_category_dict = product_category_instance.to_dict() # create an instance of ProductCategory from a dict -product_category_form_dict = product_category.from_dict(product_category_dict) +product_category_from_dict = ProductCategory.from_dict(product_category_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_location_api/docs/ProductCategoryEnum.md b/pnap_location_api/docs/ProductCategoryEnum.md index e41173fb..416fcd5f 100644 --- a/pnap_location_api/docs/ProductCategoryEnum.md +++ b/pnap_location_api/docs/ProductCategoryEnum.md @@ -2,10 +2,17 @@ The product category. -## Properties +## Enum -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- +* `SERVER` (value: `'SERVER'`) + +* `BANDWIDTH` (value: `'BANDWIDTH'`) + +* `OPERATING_SYSTEM` (value: `'OPERATING_SYSTEM'`) + +* `PUBLIC_IP` (value: `'PUBLIC_IP'`) + +* `STORAGE` (value: `'STORAGE'`) [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_location_api/docs/ProductLocationEnum.md b/pnap_location_api/docs/ProductLocationEnum.md new file mode 100644 index 00000000..a5913fc2 --- /dev/null +++ b/pnap_location_api/docs/ProductLocationEnum.md @@ -0,0 +1,21 @@ +# ProductLocationEnum + +This enum is used only in product-related schemas and contains only currently active and supported locations. Deprecated or retired locations are intentionally excluded and will not appear in create/update operations. Historical data in other API responses may still reference deprecated locations, but those values are not part of this enum. + +## Enum + +* `PHX` (value: `'PHX'`) + +* `ASH` (value: `'ASH'`) + +* `NLD` (value: `'NLD'`) + +* `SGP` (value: `'SGP'`) + +* `CHI` (value: `'CHI'`) + +* `SEA` (value: `'SEA'`) + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pnap_location_api/pnap_location_api/__init__.py b/pnap_location_api/pnap_location_api/__init__.py index ae82df97..8fafd5ce 100644 --- a/pnap_location_api/pnap_location_api/__init__.py +++ b/pnap_location_api/pnap_location_api/__init__.py @@ -15,25 +15,45 @@ """ # noqa: E501 -__version__ = "2.0.4" +__version__ = "3.0.0" + +# Define package exports +__all__ = [ + "LocationsApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "Error", + "Location", + "ProductCategory", + "ProductCategoryEnum", + "ProductLocationEnum", +] # import apis into sdk package -from pnap_location_api.api.locations_api import LocationsApi +from pnap_location_api.api.locations_api import LocationsApi as LocationsApi # import ApiClient -from pnap_location_api.api_response import ApiResponse -from pnap_location_api.api_client import ApiClient -from pnap_location_api.configuration import Configuration -from pnap_location_api.exceptions import OpenApiException -from pnap_location_api.exceptions import ApiTypeError -from pnap_location_api.exceptions import ApiValueError -from pnap_location_api.exceptions import ApiKeyError -from pnap_location_api.exceptions import ApiAttributeError -from pnap_location_api.exceptions import ApiException +from pnap_location_api.api_response import ApiResponse as ApiResponse +from pnap_location_api.api_client import ApiClient as ApiClient +from pnap_location_api.configuration import Configuration as Configuration +from pnap_location_api.exceptions import OpenApiException as OpenApiException +from pnap_location_api.exceptions import ApiTypeError as ApiTypeError +from pnap_location_api.exceptions import ApiValueError as ApiValueError +from pnap_location_api.exceptions import ApiKeyError as ApiKeyError +from pnap_location_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_location_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_location_api.models.error import Error -from pnap_location_api.models.location import Location -from pnap_location_api.models.location_enum import LocationEnum -from pnap_location_api.models.product_category import ProductCategory -from pnap_location_api.models.product_category_enum import ProductCategoryEnum +from pnap_location_api.models.error import Error as Error +from pnap_location_api.models.location import Location as Location +from pnap_location_api.models.product_category import ProductCategory as ProductCategory +from pnap_location_api.models.product_category_enum import ProductCategoryEnum as ProductCategoryEnum +from pnap_location_api.models.product_location_enum import ProductLocationEnum as ProductLocationEnum + diff --git a/pnap_location_api/pnap_location_api/api/locations_api.py b/pnap_location_api/pnap_location_api/api/locations_api.py index 602f193b..a8a825e2 100644 --- a/pnap_location_api/pnap_location_api/api/locations_api.py +++ b/pnap_location_api/pnap_location_api/api/locations_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Locations API @@ -13,26 +11,19 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated +from typing import Any, Dict, List, Optional, Tuple, Union +from typing_extensions import Annotated from pydantic import Field -from typing_extensions import Annotated from typing import List, Optional - +from typing_extensions import Annotated from pnap_location_api.models.location import Location -from pnap_location_api.models.location_enum import LocationEnum from pnap_location_api.models.product_category_enum import ProductCategoryEnum +from pnap_location_api.models.product_location_enum import ProductLocationEnum -from pnap_location_api.api_client import ApiClient +from pnap_location_api.api_client import ApiClient, RequestSerialized from pnap_location_api.api_response import ApiResponse from pnap_location_api.rest import RESTResponseType @@ -53,7 +44,7 @@ def __init__(self, api_client=None) -> None: @validate_call def get_locations( self, - location: Annotated[Optional[LocationEnum], Field(description="Location of interest")] = None, + location: Annotated[Optional[ProductLocationEnum], Field(description="Location of interest")] = None, product_category: Annotated[Optional[ProductCategoryEnum], Field(description="Product category of interest")] = None, _request_timeout: Union[ None, @@ -73,7 +64,7 @@ def get_locations( Retrieve the locations info. :param location: Location of interest - :type location: LocationEnum + :type location: ProductLocationEnum :param product_category: Product category of interest :type product_category: ProductCategoryEnum :param _request_timeout: timeout setting for this request. If one @@ -126,7 +117,7 @@ def get_locations( @validate_call def get_locations_with_http_info( self, - location: Annotated[Optional[LocationEnum], Field(description="Location of interest")] = None, + location: Annotated[Optional[ProductLocationEnum], Field(description="Location of interest")] = None, product_category: Annotated[Optional[ProductCategoryEnum], Field(description="Product category of interest")] = None, _request_timeout: Union[ None, @@ -146,7 +137,7 @@ def get_locations_with_http_info( Retrieve the locations info. :param location: Location of interest - :type location: LocationEnum + :type location: ProductLocationEnum :param product_category: Product category of interest :type product_category: ProductCategoryEnum :param _request_timeout: timeout setting for this request. If one @@ -199,7 +190,7 @@ def get_locations_with_http_info( @validate_call def get_locations_without_preload_content( self, - location: Annotated[Optional[LocationEnum], Field(description="Location of interest")] = None, + location: Annotated[Optional[ProductLocationEnum], Field(description="Location of interest")] = None, product_category: Annotated[Optional[ProductCategoryEnum], Field(description="Product category of interest")] = None, _request_timeout: Union[ None, @@ -219,7 +210,7 @@ def get_locations_without_preload_content( Retrieve the locations info. :param location: Location of interest - :type location: LocationEnum + :type location: ProductLocationEnum :param product_category: Product category of interest :type product_category: ProductCategoryEnum :param _request_timeout: timeout setting for this request. If one @@ -273,7 +264,7 @@ def _get_locations_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -284,7 +275,9 @@ def _get_locations_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -303,11 +296,12 @@ def _get_locations_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting diff --git a/pnap_location_api/pnap_location_api/api_client.py b/pnap_location_api/pnap_location_api/api_client.py index 2ef01de2..037fd323 100644 --- a/pnap_location_api/pnap_location_api/api_client.py +++ b/pnap_location_api/pnap_location_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Locations API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_location_api.configuration import Configuration -from pnap_location_api.api_response import ApiResponse +from pnap_location_api.api_response import ApiResponse, T as ApiResponseT import pnap_location_api.models from pnap_location_api import rest from pnap_location_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_location_api/2.0.4" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_location_api/3.0.0" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_location_api/2.0.4" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_location_api/3.0.0" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_location_api/pnap_location_api/api_response.py b/pnap_location_api/pnap_location_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_location_api/pnap_location_api/api_response.py +++ b/pnap_location_api/pnap_location_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_location_api/pnap_location_api/configuration.py b/pnap_location_api/pnap_location_api/configuration.py index bef10e19..e64e0751 100644 --- a/pnap_location_api/pnap_location_api/configuration.py +++ b/pnap_location_api/pnap_location_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Locations API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,113 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,19 +158,37 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/location-api/v1" if host is None else host @@ -79,6 +202,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -116,13 +242,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -134,10 +263,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -156,7 +289,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -165,8 +298,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -183,7 +316,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -197,11 +330,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -212,7 +345,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -222,7 +355,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -232,11 +365,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -248,7 +381,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -267,7 +400,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -276,7 +409,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -298,7 +431,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -309,7 +442,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -320,7 +453,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -337,7 +470,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -348,19 +483,20 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -369,10 +505,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0\n"\ - "SDK Package Version: 2.0.4".\ + "SDK Package Version: 3.0.0".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -384,7 +520,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -412,6 +553,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -424,12 +566,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_location_api/pnap_location_api/exceptions.py b/pnap_location_api/pnap_location_api/exceptions.py index a7aca14f..537174bb 100644 --- a/pnap_location_api/pnap_location_api/exceptions.py +++ b/pnap_location_api/pnap_location_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Locations API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_location_api/pnap_location_api/models/__init__.py b/pnap_location_api/pnap_location_api/models/__init__.py index 3c1fa14d..4abd9183 100644 --- a/pnap_location_api/pnap_location_api/models/__init__.py +++ b/pnap_location_api/pnap_location_api/models/__init__.py @@ -13,10 +13,10 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_location_api.models.error import Error from pnap_location_api.models.location import Location -from pnap_location_api.models.location_enum import LocationEnum from pnap_location_api.models.product_category import ProductCategory from pnap_location_api.models.product_category_enum import ProductCategoryEnum +from pnap_location_api.models.product_location_enum import ProductLocationEnum + diff --git a/pnap_location_api/pnap_location_api/models/error.py b/pnap_location_api/pnap_location_api/models/error.py index badede3f..24a65100 100644 --- a/pnap_location_api/pnap_location_api/models/error.py +++ b/pnap_location_api/pnap_location_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_location_api/pnap_location_api/models/location.py b/pnap_location_api/pnap_location_api/models/location.py index ad78c458..5b928f11 100644 --- a/pnap_location_api/pnap_location_api/models/location.py +++ b/pnap_location_api/pnap_location_api/models/location.py @@ -18,32 +18,28 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -from pnap_location_api.models.location_enum import LocationEnum from pnap_location_api.models.product_category import ProductCategory -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from pnap_location_api.models.product_location_enum import ProductLocationEnum +from typing import Optional, Set +from typing_extensions import Self class Location(BaseModel): """ Location resource """ # noqa: E501 - location: LocationEnum + location: ProductLocationEnum location_description: Optional[StrictStr] = Field(default=None, alias="locationDescription") product_categories: Optional[List[ProductCategory]] = Field(default=None, alias="productCategories") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["location", "locationDescription", "productCategories"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -56,7 +52,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Location from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -71,19 +67,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in product_categories (list) _items = [] if self.product_categories: - for _item in self.product_categories: - if _item: - _items.append(_item.to_dict()) + for _item_product_categories in self.product_categories: + if _item_product_categories: + _items.append(_item_product_categories.to_dict()) _dict['productCategories'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -93,7 +91,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Location from a dict""" if obj is None: return None @@ -104,7 +102,7 @@ def from_dict(cls, obj: Dict) -> Self: _obj = cls.model_validate({ "location": obj.get("location"), "locationDescription": obj.get("locationDescription"), - "productCategories": [ProductCategory.from_dict(_item) for _item in obj.get("productCategories")] if obj.get("productCategories") is not None else None + "productCategories": [ProductCategory.from_dict(_item) for _item in obj["productCategories"]] if obj.get("productCategories") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_location_api/pnap_location_api/models/product_category.py b/pnap_location_api/pnap_location_api/models/product_category.py index 493203ca..f3c596f0 100644 --- a/pnap_location_api/pnap_location_api/models/product_category.py +++ b/pnap_location_api/pnap_location_api/models/product_category.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from pnap_location_api.models.product_category_enum import ProductCategoryEnum -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ProductCategory(BaseModel): """ @@ -37,11 +33,11 @@ class ProductCategory(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["productCategory", "productCategoryDescription"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ProductCategory from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ProductCategory from a dict""" if obj is None: return None diff --git a/pnap_location_api/pnap_location_api/models/product_category_enum.py b/pnap_location_api/pnap_location_api/models/product_category_enum.py index d9e9b30a..859548e1 100644 --- a/pnap_location_api/pnap_location_api/models/product_category_enum.py +++ b/pnap_location_api/pnap_location_api/models/product_category_enum.py @@ -15,16 +15,8 @@ from __future__ import annotations import json -import pprint -import re # noqa: F401 from enum import Enum - - - -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing_extensions import Self class ProductCategoryEnum(str, Enum): diff --git a/pnap_location_api/pnap_location_api/models/location_enum.py b/pnap_location_api/pnap_location_api/models/product_location_enum.py similarity index 57% rename from pnap_location_api/pnap_location_api/models/location_enum.py rename to pnap_location_api/pnap_location_api/models/product_location_enum.py index d18afa9d..b6ee240b 100644 --- a/pnap_location_api/pnap_location_api/models/location_enum.py +++ b/pnap_location_api/pnap_location_api/models/product_location_enum.py @@ -15,21 +15,13 @@ from __future__ import annotations import json -import pprint -import re # noqa: F401 from enum import Enum +from typing_extensions import Self - -try: - from typing import Self -except ImportError: - from typing_extensions import Self - - -class LocationEnum(str, Enum): +class ProductLocationEnum(str, Enum): """ - The location code. + This enum is used only in product-related schemas and contains only currently active and supported locations. Deprecated or retired locations are intentionally excluded and will not appear in create/update operations. Historical data in other API responses may still reference deprecated locations, but those values are not part of this enum. """ """ @@ -41,11 +33,10 @@ class LocationEnum(str, Enum): SGP = 'SGP' CHI = 'CHI' SEA = 'SEA' - AUS = 'AUS' @classmethod def from_json(cls, json_str: str) -> Self: - """Create an instance of LocationEnum from a JSON string""" + """Create an instance of ProductLocationEnum from a JSON string""" return cls(json.loads(json_str)) diff --git a/pnap_location_api/pnap_location_api/rest.py b/pnap_location_api/pnap_location_api/rest.py index 5199ad54..cba6c59a 100644 --- a/pnap_location_api/pnap_location_api/rest.py +++ b/pnap_location_api/pnap_location_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_location_api/pnap_location_api/version.py b/pnap_location_api/pnap_location_api/version.py index c756f9c5..91c27a95 100644 --- a/pnap_location_api/pnap_location_api/version.py +++ b/pnap_location_api/pnap_location_api/version.py @@ -1 +1 @@ -VERSION = "2.0.4" \ No newline at end of file +VERSION = "3.0.0" \ No newline at end of file diff --git a/pnap_location_api/pyproject.toml b/pnap_location_api/pyproject.toml index 0975b027..6f0d367c 100644 --- a/pnap_location_api/pyproject.toml +++ b/pnap_location_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_location_api" -version = "2.0.4" +version = "3.0.0" description = "Locations API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Locations API"] -include = ["pnap_location_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_location_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_location_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_location_api/requirements.txt b/pnap_location_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_location_api/requirements.txt +++ b/pnap_location_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_location_api/setup.py b/pnap_location_api/setup.py index 224b14b0..258354fe 100644 --- a/pnap_location_api/setup.py +++ b/pnap_location_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Locations API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_location_api" -VERSION = "2.0.4" -PYTHON_REQUIRES = ">=3.7" +VERSION = "3.0.0" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) """, # noqa: E501 package_data={"pnap_location_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_network_api/README.md b/pnap_network_api/README.md index 0ebbaf71..51f3cf08 100644 --- a/pnap_network_api/README.md +++ b/pnap_network_api/README.md @@ -16,13 +16,13 @@ Helpful knowledge base articles are available for This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0 -- Package version: 3.0.1 +- Package version: 3.1.0 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -52,9 +52,16 @@ Then import the package: import pnap_network_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_network_api from pnap_network_api.rest import ApiException from pprint import pprint @@ -105,6 +112,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -136,6 +144,7 @@ Class | Method | HTTP request | Description - [AsnDetails](docs/AsnDetails.md) - [BgpIPv4Prefix](docs/BgpIPv4Prefix.md) + - [BgpIpPrefix](docs/BgpIpPrefix.md) - [BgpPeerGroup](docs/BgpPeerGroup.md) - [BgpPeerGroupCreate](docs/BgpPeerGroupCreate.md) - [BgpPeerGroupPatch](docs/BgpPeerGroupPatch.md) @@ -171,4 +180,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_network_api/docs/AsnDetails.md b/pnap_network_api/docs/AsnDetails.md index ea8d436d..cee6b37e 100644 --- a/pnap_network_api/docs/AsnDetails.md +++ b/pnap_network_api/docs/AsnDetails.md @@ -21,12 +21,12 @@ json = "{}" # create an instance of AsnDetails from a JSON string asn_details_instance = AsnDetails.from_json(json) # print the JSON string representation of the object -print AsnDetails.to_json() +print(AsnDetails.to_json()) # convert the object into a dict asn_details_dict = asn_details_instance.to_dict() # create an instance of AsnDetails from a dict -asn_details_form_dict = asn_details.from_dict(asn_details_dict) +asn_details_from_dict = AsnDetails.from_dict(asn_details_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/BGPPeerGroupsApi.md b/pnap_network_api/docs/BGPPeerGroupsApi.md index 2081b0b7..6789512e 100644 --- a/pnap_network_api/docs/BGPPeerGroupsApi.md +++ b/pnap_network_api/docs/BGPPeerGroupsApi.md @@ -23,8 +23,6 @@ List all BGP Peer Groups owned by account. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.bgp_peer_group import BgpPeerGroup from pnap_network_api.rest import ApiException @@ -104,8 +102,6 @@ Deletes BGP Peer Group by ID. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.bgp_peer_group import BgpPeerGroup from pnap_network_api.rest import ApiException @@ -166,6 +162,7 @@ Name | Type | Description | Notes | Status code | Description | Response headers | |-------------|-------------|------------------| **202** | Request to delete BGP Peer Group is accepted. | - | +**204** | The BGP Peer Group has been deleted. | - | **400** | The request failed due to wrong data. Please check the provided parameters and try again. | - | **401** | The request failed due to invalid credentials. Please check the provided credentials and try again. | - | **403** | The request failed since this resource cannot be accessed by the provided credentials. | - | @@ -186,8 +183,6 @@ Retrieves BGP Peer Group by ID. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.bgp_peer_group import BgpPeerGroup from pnap_network_api.rest import ApiException @@ -267,8 +262,6 @@ Modifies BGP Peer Group by ID. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.bgp_peer_group import BgpPeerGroup from pnap_network_api.models.bgp_peer_group_patch import BgpPeerGroupPatch @@ -352,8 +345,6 @@ Create a BGP Peer Group. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.bgp_peer_group import BgpPeerGroup from pnap_network_api.models.bgp_peer_group_create import BgpPeerGroupCreate diff --git a/pnap_network_api/docs/BgpIPv4Prefix.md b/pnap_network_api/docs/BgpIPv4Prefix.md index b296adec..7280a64a 100644 --- a/pnap_network_api/docs/BgpIPv4Prefix.md +++ b/pnap_network_api/docs/BgpIPv4Prefix.md @@ -1,6 +1,6 @@ # BgpIPv4Prefix -The BGP IPv4 Prefix. +The BGP IPv4 Prefix. Deprecated in favour of generic BgpIpPrefix. ## Properties @@ -22,12 +22,12 @@ json = "{}" # create an instance of BgpIPv4Prefix from a JSON string bgp_ipv4_prefix_instance = BgpIPv4Prefix.from_json(json) # print the JSON string representation of the object -print BgpIPv4Prefix.to_json() +print(BgpIPv4Prefix.to_json()) # convert the object into a dict bgp_ipv4_prefix_dict = bgp_ipv4_prefix_instance.to_dict() # create an instance of BgpIPv4Prefix from a dict -bgp_ipv4_prefix_form_dict = bgp_ipv4_prefix.from_dict(bgp_ipv4_prefix_dict) +bgp_ipv4_prefix_from_dict = BgpIPv4Prefix.from_dict(bgp_ipv4_prefix_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/BgpIpPrefix.md b/pnap_network_api/docs/BgpIpPrefix.md new file mode 100644 index 00000000..0a6772de --- /dev/null +++ b/pnap_network_api/docs/BgpIpPrefix.md @@ -0,0 +1,33 @@ +# BgpIpPrefix + +The BGP IP Prefix. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ip_allocation_id** | **str** | IP allocation ID. | +**cidr** | **str** | The IP block in CIDR format, dependent on IP version. | +**ip_version** | **str** | The IP block version. | +**status** | **str** | The BGP IP Prefix status. Can have one of the following values: `PENDING`, `BUSY`, `READY`, `ERROR` and `DELETING`. | + +## Example + +```python +from pnap_network_api.models.bgp_ip_prefix import BgpIpPrefix + +# TODO update the JSON string below +json = "{}" +# create an instance of BgpIpPrefix from a JSON string +bgp_ip_prefix_instance = BgpIpPrefix.from_json(json) +# print the JSON string representation of the object +print(BgpIpPrefix.to_json()) + +# convert the object into a dict +bgp_ip_prefix_dict = bgp_ip_prefix_instance.to_dict() +# create an instance of BgpIpPrefix from a dict +bgp_ip_prefix_from_dict = BgpIpPrefix.from_dict(bgp_ip_prefix_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pnap_network_api/docs/BgpPeerGroup.md b/pnap_network_api/docs/BgpPeerGroup.md index f2ade83a..9bf0ba4e 100644 --- a/pnap_network_api/docs/BgpPeerGroup.md +++ b/pnap_network_api/docs/BgpPeerGroup.md @@ -8,8 +8,9 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **str** | The unique identifier of the BGP Peer Group. | **status** | **str** | The BGP Peer Group status. Can have one of the following values: `PENDING`, `ON_HOLD`, `BUSY`, `READY`, `ERROR`, `PENDING_DELETION` and `DELETING`. | -**location** | **str** | The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. | -**ipv4_prefixes** | [**List[BgpIPv4Prefix]**](BgpIPv4Prefix.md) | The List of the BGP Peer Group IPv4 prefixes. | +**location** | **str** | The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. | +**ipv4_prefixes** | [**List[BgpIPv4Prefix]**](BgpIPv4Prefix.md) | The List of the BGP Peer Group IPv4 prefixes. Deprecated in favour of generic ipPrefixes. | +**ip_prefixes** | [**List[BgpIpPrefix]**](BgpIpPrefix.md) | The List of the BGP Peer Group IP prefixes. | **target_asn_details** | [**AsnDetails**](AsnDetails.md) | | **active_asn_details** | [**AsnDetails**](AsnDetails.md) | | [optional] **password** | **str** | The BGP Peer Group password. | @@ -17,6 +18,7 @@ Name | Type | Description | Notes **rpki_roa_origin_asn** | **int** | The RPKI ROA Origin ASN of the BGP Peer Group based on location. | **e_bgp_multi_hop** | **int** | The eBGP Multi-hop of the BGP Peer Group. | **peering_loopbacks_v4** | **List[str]** | The IPv4 Peering Loopback addresses of the BGP Peer Group. Valid IP formats are IPv4 addresses. | +**peering_loopbacks_v6** | **List[str]** | The IPv6 Peering Loopback addresses of the BGP Peer Group. Valid IP formats are IPv6 addresses. | **keep_alive_timer_seconds** | **int** | The Keep Alive Timer in seconds of the BGP Peer Group. | **hold_timer_seconds** | **int** | The Hold Timer in seconds of the BGP Peer Group. | **created_on** | **str** | Date and time of creation. | [optional] @@ -32,12 +34,12 @@ json = "{}" # create an instance of BgpPeerGroup from a JSON string bgp_peer_group_instance = BgpPeerGroup.from_json(json) # print the JSON string representation of the object -print BgpPeerGroup.to_json() +print(BgpPeerGroup.to_json()) # convert the object into a dict bgp_peer_group_dict = bgp_peer_group_instance.to_dict() # create an instance of BgpPeerGroup from a dict -bgp_peer_group_form_dict = bgp_peer_group.from_dict(bgp_peer_group_dict) +bgp_peer_group_from_dict = BgpPeerGroup.from_dict(bgp_peer_group_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/BgpPeerGroupCreate.md b/pnap_network_api/docs/BgpPeerGroupCreate.md index 6639f1c8..1376b048 100644 --- a/pnap_network_api/docs/BgpPeerGroupCreate.md +++ b/pnap_network_api/docs/BgpPeerGroupCreate.md @@ -6,7 +6,7 @@ Create a BGP Peer Group. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**location** | **str** | The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. | +**location** | **str** | The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. | **asn** | **int** | The BGP Peer Group ASN. | [default to 65401] **password** | **str** | The BGP Peer Group password. | [optional] **advertised_routes** | **str** | The Advertised routes for the BGP Peer Group. Can have one of the following values: `DEFAULT` and `NONE`. | [default to 'NONE'] @@ -21,12 +21,12 @@ json = "{}" # create an instance of BgpPeerGroupCreate from a JSON string bgp_peer_group_create_instance = BgpPeerGroupCreate.from_json(json) # print the JSON string representation of the object -print BgpPeerGroupCreate.to_json() +print(BgpPeerGroupCreate.to_json()) # convert the object into a dict bgp_peer_group_create_dict = bgp_peer_group_create_instance.to_dict() # create an instance of BgpPeerGroupCreate from a dict -bgp_peer_group_create_form_dict = bgp_peer_group_create.from_dict(bgp_peer_group_create_dict) +bgp_peer_group_create_from_dict = BgpPeerGroupCreate.from_dict(bgp_peer_group_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/BgpPeerGroupPatch.md b/pnap_network_api/docs/BgpPeerGroupPatch.md index da8a64ce..b75bc563 100644 --- a/pnap_network_api/docs/BgpPeerGroupPatch.md +++ b/pnap_network_api/docs/BgpPeerGroupPatch.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of BgpPeerGroupPatch from a JSON string bgp_peer_group_patch_instance = BgpPeerGroupPatch.from_json(json) # print the JSON string representation of the object -print BgpPeerGroupPatch.to_json() +print(BgpPeerGroupPatch.to_json()) # convert the object into a dict bgp_peer_group_patch_dict = bgp_peer_group_patch_instance.to_dict() # create an instance of BgpPeerGroupPatch from a dict -bgp_peer_group_patch_form_dict = bgp_peer_group_patch.from_dict(bgp_peer_group_patch_dict) +bgp_peer_group_patch_from_dict = BgpPeerGroupPatch.from_dict(bgp_peer_group_patch_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/Error.md b/pnap_network_api/docs/Error.md index 7949f735..5d13b3f4 100644 --- a/pnap_network_api/docs/Error.md +++ b/pnap_network_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/NetworkMembership.md b/pnap_network_api/docs/NetworkMembership.md index c94cbd5a..acfec153 100644 --- a/pnap_network_api/docs/NetworkMembership.md +++ b/pnap_network_api/docs/NetworkMembership.md @@ -7,7 +7,7 @@ Resource details linked to the Network. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **resource_id** | **str** | The resource identifier. | -**resource_type** | **str** | The resource's type. | +**resource_type** | **str** | The resource's type. Can have one of the following values: `server`, `storage` or `virtual`. | **ips** | **List[str]** | List of IPs associated to the resource. | ## Example @@ -20,12 +20,12 @@ json = "{}" # create an instance of NetworkMembership from a JSON string network_membership_instance = NetworkMembership.from_json(json) # print the JSON string representation of the object -print NetworkMembership.to_json() +print(NetworkMembership.to_json()) # convert the object into a dict network_membership_dict = network_membership_instance.to_dict() # create an instance of NetworkMembership from a dict -network_membership_form_dict = network_membership.from_dict(network_membership_dict) +network_membership_from_dict = NetworkMembership.from_dict(network_membership_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PrivateNetwork.md b/pnap_network_api/docs/PrivateNetwork.md index 5e9d3d2a..a63aa53a 100644 --- a/pnap_network_api/docs/PrivateNetwork.md +++ b/pnap_network_api/docs/PrivateNetwork.md @@ -29,12 +29,12 @@ json = "{}" # create an instance of PrivateNetwork from a JSON string private_network_instance = PrivateNetwork.from_json(json) # print the JSON string representation of the object -print PrivateNetwork.to_json() +print(PrivateNetwork.to_json()) # convert the object into a dict private_network_dict = private_network_instance.to_dict() # create an instance of PrivateNetwork from a dict -private_network_form_dict = private_network.from_dict(private_network_dict) +private_network_from_dict = PrivateNetwork.from_dict(private_network_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PrivateNetworkCreate.md b/pnap_network_api/docs/PrivateNetworkCreate.md index 1dd2e2ee..1032640e 100644 --- a/pnap_network_api/docs/PrivateNetworkCreate.md +++ b/pnap_network_api/docs/PrivateNetworkCreate.md @@ -8,7 +8,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **name** | **str** | The friendly name of this private network. This name should be unique. | **description** | **str** | The description of this private network. | [optional] -**location** | **str** | The location of this private network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. | +**location** | **str** | The location of this private network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. | **location_default** | **bool** | Identifies network as the default private network for the specified location. | [optional] [default to False] **vlan_id** | **int** | The VLAN that will be assigned to this network. | [optional] **cidr** | **str** | IP range associated with this private network in CIDR notation.<br> Setting the `force` query parameter to `true` allows you to skip assigning a specific IP range to network. | [optional] @@ -23,12 +23,12 @@ json = "{}" # create an instance of PrivateNetworkCreate from a JSON string private_network_create_instance = PrivateNetworkCreate.from_json(json) # print the JSON string representation of the object -print PrivateNetworkCreate.to_json() +print(PrivateNetworkCreate.to_json()) # convert the object into a dict private_network_create_dict = private_network_create_instance.to_dict() # create an instance of PrivateNetworkCreate from a dict -private_network_create_form_dict = private_network_create.from_dict(private_network_create_dict) +private_network_create_from_dict = PrivateNetworkCreate.from_dict(private_network_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PrivateNetworkModify.md b/pnap_network_api/docs/PrivateNetworkModify.md index c9b93579..032561af 100644 --- a/pnap_network_api/docs/PrivateNetworkModify.md +++ b/pnap_network_api/docs/PrivateNetworkModify.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of PrivateNetworkModify from a JSON string private_network_modify_instance = PrivateNetworkModify.from_json(json) # print the JSON string representation of the object -print PrivateNetworkModify.to_json() +print(PrivateNetworkModify.to_json()) # convert the object into a dict private_network_modify_dict = private_network_modify_instance.to_dict() # create an instance of PrivateNetworkModify from a dict -private_network_modify_form_dict = private_network_modify.from_dict(private_network_modify_dict) +private_network_modify_from_dict = PrivateNetworkModify.from_dict(private_network_modify_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PrivateNetworkServer.md b/pnap_network_api/docs/PrivateNetworkServer.md index d1516ddb..4f066e4d 100644 --- a/pnap_network_api/docs/PrivateNetworkServer.md +++ b/pnap_network_api/docs/PrivateNetworkServer.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of PrivateNetworkServer from a JSON string private_network_server_instance = PrivateNetworkServer.from_json(json) # print the JSON string representation of the object -print PrivateNetworkServer.to_json() +print(PrivateNetworkServer.to_json()) # convert the object into a dict private_network_server_dict = private_network_server_instance.to_dict() # create an instance of PrivateNetworkServer from a dict -private_network_server_form_dict = private_network_server.from_dict(private_network_server_dict) +private_network_server_from_dict = PrivateNetworkServer.from_dict(private_network_server_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PrivateNetworksApi.md b/pnap_network_api/docs/PrivateNetworksApi.md index d101d6cb..0540d5f9 100644 --- a/pnap_network_api/docs/PrivateNetworksApi.md +++ b/pnap_network_api/docs/PrivateNetworksApi.md @@ -23,8 +23,6 @@ List all Private Networks owned by account. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.private_network import PrivateNetwork from pnap_network_api.rest import ApiException @@ -104,8 +102,6 @@ Delete Private Network. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.rest import ApiException from pprint import pprint @@ -182,8 +178,6 @@ Retrieve Private Network Details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.private_network import PrivateNetwork from pnap_network_api.rest import ApiException @@ -262,8 +256,6 @@ Update Private Network Details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.private_network import PrivateNetwork from pnap_network_api.models.private_network_modify import PrivateNetworkModify @@ -346,8 +338,6 @@ Create a Private Network. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.private_network import PrivateNetwork from pnap_network_api.models.private_network_create import PrivateNetworkCreate diff --git a/pnap_network_api/docs/PublicNetwork.md b/pnap_network_api/docs/PublicNetwork.md index 5e215d33..9ec2c9d0 100644 --- a/pnap_network_api/docs/PublicNetwork.md +++ b/pnap_network_api/docs/PublicNetwork.md @@ -10,7 +10,7 @@ Name | Type | Description | Notes **vlan_id** | **int** | The VLAN of this public network. | **memberships** | [**List[NetworkMembership]**](NetworkMembership.md) | A list of resources that are members of this public network. | **name** | **str** | The friendly name of this public network. | -**location** | **str** | The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. | +**location** | **str** | The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. | **description** | **str** | The description of this public network. | [optional] **status** | **str** | The status of the public network. Can have one of the following values: `BUSY`, `READY`, `DELETING` or `ERROR`. | **created_on** | **datetime** | Date and time when this public network was created. | @@ -27,12 +27,12 @@ json = "{}" # create an instance of PublicNetwork from a JSON string public_network_instance = PublicNetwork.from_json(json) # print the JSON string representation of the object -print PublicNetwork.to_json() +print(PublicNetwork.to_json()) # convert the object into a dict public_network_dict = public_network_instance.to_dict() # create an instance of PublicNetwork from a dict -public_network_form_dict = public_network.from_dict(public_network_dict) +public_network_from_dict = PublicNetwork.from_dict(public_network_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PublicNetworkCreate.md b/pnap_network_api/docs/PublicNetworkCreate.md index f22ff7df..60457b2a 100644 --- a/pnap_network_api/docs/PublicNetworkCreate.md +++ b/pnap_network_api/docs/PublicNetworkCreate.md @@ -8,7 +8,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **name** | **str** | The friendly name of this public network. This name should be unique. | **description** | **str** | The description of this public network. | [optional] -**location** | **str** | The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. | +**location** | **str** | The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. | **vlan_id** | **int** | The VLAN that will be assigned to this network. | [optional] **ip_blocks** | [**List[PublicNetworkIpBlockCreate]**](PublicNetworkIpBlockCreate.md) | A list of IP Blocks that will be associated with this public network. Supported maximum of 10 IPv4 Blocks and 1 IPv6 Block. | [optional] **ra_enabled** | **bool** | Boolean indicating whether Router Advertisement is enabled. Only applicable for Network with IPv6 Blocks. | [optional] @@ -23,12 +23,12 @@ json = "{}" # create an instance of PublicNetworkCreate from a JSON string public_network_create_instance = PublicNetworkCreate.from_json(json) # print the JSON string representation of the object -print PublicNetworkCreate.to_json() +print(PublicNetworkCreate.to_json()) # convert the object into a dict public_network_create_dict = public_network_create_instance.to_dict() # create an instance of PublicNetworkCreate from a dict -public_network_create_form_dict = public_network_create.from_dict(public_network_create_dict) +public_network_create_from_dict = PublicNetworkCreate.from_dict(public_network_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PublicNetworkIpBlock.md b/pnap_network_api/docs/PublicNetworkIpBlock.md index 32e67c84..6231dab9 100644 --- a/pnap_network_api/docs/PublicNetworkIpBlock.md +++ b/pnap_network_api/docs/PublicNetworkIpBlock.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of PublicNetworkIpBlock from a JSON string public_network_ip_block_instance = PublicNetworkIpBlock.from_json(json) # print the JSON string representation of the object -print PublicNetworkIpBlock.to_json() +print(PublicNetworkIpBlock.to_json()) # convert the object into a dict public_network_ip_block_dict = public_network_ip_block_instance.to_dict() # create an instance of PublicNetworkIpBlock from a dict -public_network_ip_block_form_dict = public_network_ip_block.from_dict(public_network_ip_block_dict) +public_network_ip_block_from_dict = PublicNetworkIpBlock.from_dict(public_network_ip_block_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PublicNetworkIpBlockCreate.md b/pnap_network_api/docs/PublicNetworkIpBlockCreate.md index f200d2e7..dc2ac3f9 100644 --- a/pnap_network_api/docs/PublicNetworkIpBlockCreate.md +++ b/pnap_network_api/docs/PublicNetworkIpBlockCreate.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of PublicNetworkIpBlockCreate from a JSON string public_network_ip_block_create_instance = PublicNetworkIpBlockCreate.from_json(json) # print the JSON string representation of the object -print PublicNetworkIpBlockCreate.to_json() +print(PublicNetworkIpBlockCreate.to_json()) # convert the object into a dict public_network_ip_block_create_dict = public_network_ip_block_create_instance.to_dict() # create an instance of PublicNetworkIpBlockCreate from a dict -public_network_ip_block_create_form_dict = public_network_ip_block_create.from_dict(public_network_ip_block_create_dict) +public_network_ip_block_create_from_dict = PublicNetworkIpBlockCreate.from_dict(public_network_ip_block_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PublicNetworkModify.md b/pnap_network_api/docs/PublicNetworkModify.md index c8404029..f57bd047 100644 --- a/pnap_network_api/docs/PublicNetworkModify.md +++ b/pnap_network_api/docs/PublicNetworkModify.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of PublicNetworkModify from a JSON string public_network_modify_instance = PublicNetworkModify.from_json(json) # print the JSON string representation of the object -print PublicNetworkModify.to_json() +print(PublicNetworkModify.to_json()) # convert the object into a dict public_network_modify_dict = public_network_modify_instance.to_dict() # create an instance of PublicNetworkModify from a dict -public_network_modify_form_dict = public_network_modify.from_dict(public_network_modify_dict) +public_network_modify_from_dict = PublicNetworkModify.from_dict(public_network_modify_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_api/docs/PublicNetworksApi.md b/pnap_network_api/docs/PublicNetworksApi.md index e3b74ec9..9c2054ba 100644 --- a/pnap_network_api/docs/PublicNetworksApi.md +++ b/pnap_network_api/docs/PublicNetworksApi.md @@ -25,8 +25,6 @@ List all Public Networks owned by account. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.public_network import PublicNetwork from pnap_network_api.rest import ApiException @@ -106,8 +104,6 @@ Delete Public Network. The request is accepted only if no resources are members * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.rest import ApiException from pprint import pprint @@ -185,8 +181,6 @@ Retrieve Public Network Details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.public_network import PublicNetwork from pnap_network_api.rest import ApiException @@ -265,8 +259,6 @@ Removes the IP Block from the Public Network.
Please ensure that no resource * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.rest import ApiException from pprint import pprint @@ -350,8 +342,6 @@ Adds an IP block to this public network. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.public_network_ip_block import PublicNetworkIpBlock from pnap_network_api.models.public_network_ip_block_create import PublicNetworkIpBlockCreate @@ -435,8 +425,6 @@ Update Public Network's Details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.public_network import PublicNetwork from pnap_network_api.models.public_network_modify import PublicNetworkModify @@ -521,8 +509,6 @@ Create a public network. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_api from pnap_network_api.models.public_network import PublicNetwork from pnap_network_api.models.public_network_create import PublicNetworkCreate diff --git a/pnap_network_api/pnap_network_api/__init__.py b/pnap_network_api/pnap_network_api/__init__.py index bc0e84d7..2de38ef1 100644 --- a/pnap_network_api/pnap_network_api/__init__.py +++ b/pnap_network_api/pnap_network_api/__init__.py @@ -15,38 +15,73 @@ """ # noqa: E501 -__version__ = "3.0.1" +__version__ = "3.1.0" + +# Define package exports +__all__ = [ + "BGPPeerGroupsApi", + "PrivateNetworksApi", + "PublicNetworksApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "AsnDetails", + "BgpIPv4Prefix", + "BgpIpPrefix", + "BgpPeerGroup", + "BgpPeerGroupCreate", + "BgpPeerGroupPatch", + "Error", + "NetworkMembership", + "PrivateNetwork", + "PrivateNetworkCreate", + "PrivateNetworkModify", + "PrivateNetworkServer", + "PublicNetwork", + "PublicNetworkCreate", + "PublicNetworkIpBlock", + "PublicNetworkIpBlockCreate", + "PublicNetworkModify", +] # import apis into sdk package -from pnap_network_api.api.bgp_peer_groups_api import BGPPeerGroupsApi -from pnap_network_api.api.private_networks_api import PrivateNetworksApi -from pnap_network_api.api.public_networks_api import PublicNetworksApi +from pnap_network_api.api.bgp_peer_groups_api import BGPPeerGroupsApi as BGPPeerGroupsApi +from pnap_network_api.api.private_networks_api import PrivateNetworksApi as PrivateNetworksApi +from pnap_network_api.api.public_networks_api import PublicNetworksApi as PublicNetworksApi # import ApiClient -from pnap_network_api.api_response import ApiResponse -from pnap_network_api.api_client import ApiClient -from pnap_network_api.configuration import Configuration -from pnap_network_api.exceptions import OpenApiException -from pnap_network_api.exceptions import ApiTypeError -from pnap_network_api.exceptions import ApiValueError -from pnap_network_api.exceptions import ApiKeyError -from pnap_network_api.exceptions import ApiAttributeError -from pnap_network_api.exceptions import ApiException +from pnap_network_api.api_response import ApiResponse as ApiResponse +from pnap_network_api.api_client import ApiClient as ApiClient +from pnap_network_api.configuration import Configuration as Configuration +from pnap_network_api.exceptions import OpenApiException as OpenApiException +from pnap_network_api.exceptions import ApiTypeError as ApiTypeError +from pnap_network_api.exceptions import ApiValueError as ApiValueError +from pnap_network_api.exceptions import ApiKeyError as ApiKeyError +from pnap_network_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_network_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_network_api.models.asn_details import AsnDetails -from pnap_network_api.models.bgp_ipv4_prefix import BgpIPv4Prefix -from pnap_network_api.models.bgp_peer_group import BgpPeerGroup -from pnap_network_api.models.bgp_peer_group_create import BgpPeerGroupCreate -from pnap_network_api.models.bgp_peer_group_patch import BgpPeerGroupPatch -from pnap_network_api.models.error import Error -from pnap_network_api.models.network_membership import NetworkMembership -from pnap_network_api.models.private_network import PrivateNetwork -from pnap_network_api.models.private_network_create import PrivateNetworkCreate -from pnap_network_api.models.private_network_modify import PrivateNetworkModify -from pnap_network_api.models.private_network_server import PrivateNetworkServer -from pnap_network_api.models.public_network import PublicNetwork -from pnap_network_api.models.public_network_create import PublicNetworkCreate -from pnap_network_api.models.public_network_ip_block import PublicNetworkIpBlock -from pnap_network_api.models.public_network_ip_block_create import PublicNetworkIpBlockCreate -from pnap_network_api.models.public_network_modify import PublicNetworkModify +from pnap_network_api.models.asn_details import AsnDetails as AsnDetails +from pnap_network_api.models.bgp_ipv4_prefix import BgpIPv4Prefix as BgpIPv4Prefix +from pnap_network_api.models.bgp_ip_prefix import BgpIpPrefix as BgpIpPrefix +from pnap_network_api.models.bgp_peer_group import BgpPeerGroup as BgpPeerGroup +from pnap_network_api.models.bgp_peer_group_create import BgpPeerGroupCreate as BgpPeerGroupCreate +from pnap_network_api.models.bgp_peer_group_patch import BgpPeerGroupPatch as BgpPeerGroupPatch +from pnap_network_api.models.error import Error as Error +from pnap_network_api.models.network_membership import NetworkMembership as NetworkMembership +from pnap_network_api.models.private_network import PrivateNetwork as PrivateNetwork +from pnap_network_api.models.private_network_create import PrivateNetworkCreate as PrivateNetworkCreate +from pnap_network_api.models.private_network_modify import PrivateNetworkModify as PrivateNetworkModify +from pnap_network_api.models.private_network_server import PrivateNetworkServer as PrivateNetworkServer +from pnap_network_api.models.public_network import PublicNetwork as PublicNetwork +from pnap_network_api.models.public_network_create import PublicNetworkCreate as PublicNetworkCreate +from pnap_network_api.models.public_network_ip_block import PublicNetworkIpBlock as PublicNetworkIpBlock +from pnap_network_api.models.public_network_ip_block_create import PublicNetworkIpBlockCreate as PublicNetworkIpBlockCreate +from pnap_network_api.models.public_network_modify import PublicNetworkModify as PublicNetworkModify + diff --git a/pnap_network_api/pnap_network_api/api/bgp_peer_groups_api.py b/pnap_network_api/pnap_network_api/api/bgp_peer_groups_api.py index 51c32759..2d3faae5 100644 --- a/pnap_network_api/pnap_network_api/api/bgp_peer_groups_api.py +++ b/pnap_network_api/pnap_network_api/api/bgp_peer_groups_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Networks API @@ -13,28 +11,19 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictStr +from pydantic import Field, StrictStr from typing import List, Optional - +from typing_extensions import Annotated from pnap_network_api.models.bgp_peer_group import BgpPeerGroup from pnap_network_api.models.bgp_peer_group_create import BgpPeerGroupCreate from pnap_network_api.models.bgp_peer_group_patch import BgpPeerGroupPatch -from pnap_network_api.api_client import ApiClient +from pnap_network_api.api_client import ApiClient, RequestSerialized from pnap_network_api.api_response import ApiResponse from pnap_network_api.rest import RESTResponseType @@ -268,7 +257,7 @@ def _bgp_peer_groups_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -279,7 +268,9 @@ def _bgp_peer_groups_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -294,11 +285,12 @@ def _bgp_peer_groups_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -379,6 +371,7 @@ def bgp_peer_groups_peer_group_id_delete( _response_types_map: Dict[str, Optional[str]] = { '202': "BgpPeerGroup", + '204': None, '400': "Error", '401': "Error", '403': "Error", @@ -451,6 +444,7 @@ def bgp_peer_groups_peer_group_id_delete_with_http_info( _response_types_map: Dict[str, Optional[str]] = { '202': "BgpPeerGroup", + '204': None, '400': "Error", '401': "Error", '403': "Error", @@ -523,6 +517,7 @@ def bgp_peer_groups_peer_group_id_delete_without_preload_content( _response_types_map: Dict[str, Optional[str]] = { '202': "BgpPeerGroup", + '204': None, '400': "Error", '401': "Error", '403': "Error", @@ -543,7 +538,7 @@ def _bgp_peer_groups_peer_group_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -554,7 +549,9 @@ def _bgp_peer_groups_peer_group_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -567,11 +564,12 @@ def _bgp_peer_groups_peer_group_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -813,7 +811,7 @@ def _bgp_peer_groups_peer_group_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -824,7 +822,9 @@ def _bgp_peer_groups_peer_group_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -837,11 +837,12 @@ def _bgp_peer_groups_peer_group_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1099,7 +1100,7 @@ def _bgp_peer_groups_peer_group_id_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1110,7 +1111,9 @@ def _bgp_peer_groups_peer_group_id_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1125,11 +1128,12 @@ def _bgp_peer_groups_peer_group_id_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1390,7 +1394,7 @@ def _bgp_peer_groups_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1401,7 +1405,9 @@ def _bgp_peer_groups_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1414,11 +1420,12 @@ def _bgp_peer_groups_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_network_api/pnap_network_api/api/private_networks_api.py b/pnap_network_api/pnap_network_api/api/private_networks_api.py index ad88197e..8d7b2e4a 100644 --- a/pnap_network_api/pnap_network_api/api/private_networks_api.py +++ b/pnap_network_api/pnap_network_api/api/private_networks_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Networks API @@ -13,28 +11,19 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictBool, StrictStr +from pydantic import Field, StrictBool, StrictStr from typing import List, Optional - +from typing_extensions import Annotated from pnap_network_api.models.private_network import PrivateNetwork from pnap_network_api.models.private_network_create import PrivateNetworkCreate from pnap_network_api.models.private_network_modify import PrivateNetworkModify -from pnap_network_api.api_client import ApiClient +from pnap_network_api.api_client import ApiClient, RequestSerialized from pnap_network_api.api_response import ApiResponse from pnap_network_api.rest import RESTResponseType @@ -268,7 +257,7 @@ def _private_networks_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -279,7 +268,9 @@ def _private_networks_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -294,11 +285,12 @@ def _private_networks_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -540,7 +532,7 @@ def _private_networks_network_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -551,7 +543,9 @@ def _private_networks_network_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -564,11 +558,12 @@ def _private_networks_network_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -807,7 +802,7 @@ def _private_networks_network_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -818,7 +813,9 @@ def _private_networks_network_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -831,11 +828,12 @@ def _private_networks_network_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1090,7 +1088,7 @@ def _private_networks_network_id_put_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1101,7 +1099,9 @@ def _private_networks_network_id_put_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1116,11 +1116,12 @@ def _private_networks_network_id_put_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1388,7 +1389,7 @@ def _private_networks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1399,7 +1400,9 @@ def _private_networks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1416,11 +1419,12 @@ def _private_networks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_network_api/pnap_network_api/api/public_networks_api.py b/pnap_network_api/pnap_network_api/api/public_networks_api.py index 51af80a6..15077104 100644 --- a/pnap_network_api/pnap_network_api/api/public_networks_api.py +++ b/pnap_network_api/pnap_network_api/api/public_networks_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Networks API @@ -13,30 +11,21 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictBool, StrictStr +from pydantic import Field, StrictBool, StrictStr from typing import List, Optional - +from typing_extensions import Annotated from pnap_network_api.models.public_network import PublicNetwork from pnap_network_api.models.public_network_create import PublicNetworkCreate from pnap_network_api.models.public_network_ip_block import PublicNetworkIpBlock from pnap_network_api.models.public_network_ip_block_create import PublicNetworkIpBlockCreate from pnap_network_api.models.public_network_modify import PublicNetworkModify -from pnap_network_api.api_client import ApiClient +from pnap_network_api.api_client import ApiClient, RequestSerialized from pnap_network_api.api_response import ApiResponse from pnap_network_api.rest import RESTResponseType @@ -270,7 +259,7 @@ def _public_networks_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -281,7 +270,9 @@ def _public_networks_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -296,11 +287,12 @@ def _public_networks_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -545,7 +537,7 @@ def _public_networks_network_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -556,7 +548,9 @@ def _public_networks_network_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -569,11 +563,12 @@ def _public_networks_network_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -812,7 +807,7 @@ def _public_networks_network_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -823,7 +818,9 @@ def _public_networks_network_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -836,11 +833,12 @@ def _public_networks_network_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1111,7 +1109,7 @@ def _public_networks_network_id_ip_blocks_ip_block_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1122,7 +1120,9 @@ def _public_networks_network_id_ip_blocks_ip_block_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1141,11 +1141,12 @@ def _public_networks_network_id_ip_blocks_ip_block_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1403,7 +1404,7 @@ def _public_networks_network_id_ip_blocks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1414,7 +1415,9 @@ def _public_networks_network_id_ip_blocks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1429,11 +1432,12 @@ def _public_networks_network_id_ip_blocks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1707,7 +1711,7 @@ def _public_networks_network_id_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1718,7 +1722,9 @@ def _public_networks_network_id_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1733,11 +1739,12 @@ def _public_networks_network_id_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1995,7 +2002,7 @@ def _public_networks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2006,7 +2013,9 @@ def _public_networks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2019,11 +2028,12 @@ def _public_networks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_network_api/pnap_network_api/api_client.py b/pnap_network_api/pnap_network_api/api_client.py index e041725d..84e7ea21 100644 --- a/pnap_network_api/pnap_network_api/api_client.py +++ b/pnap_network_api/pnap_network_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Networks API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_network_api.configuration import Configuration -from pnap_network_api.api_response import ApiResponse +from pnap_network_api.api_response import ApiResponse, T as ApiResponseT import pnap_network_api.models from pnap_network_api import rest from pnap_network_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_network_api/3.0.1" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_network_api/3.1.0" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_network_api/3.0.1" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_network_api/3.1.0" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_network_api/pnap_network_api/api_response.py b/pnap_network_api/pnap_network_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_network_api/pnap_network_api/api_response.py +++ b/pnap_network_api/pnap_network_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_network_api/pnap_network_api/configuration.py b/pnap_network_api/pnap_network_api/configuration.py index 0c225aa3..9885feb4 100644 --- a/pnap_network_api/pnap_network_api/configuration.py +++ b/pnap_network_api/pnap_network_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Networks API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/networks/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0\n"\ - "SDK Package Version: 3.0.1".\ + "SDK Package Version: 3.1.0".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_network_api/pnap_network_api/exceptions.py b/pnap_network_api/pnap_network_api/exceptions.py index a2a19e78..479416a6 100644 --- a/pnap_network_api/pnap_network_api/exceptions.py +++ b/pnap_network_api/pnap_network_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Networks API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_network_api/pnap_network_api/models/__init__.py b/pnap_network_api/pnap_network_api/models/__init__.py index 3845311e..89b3f1e6 100644 --- a/pnap_network_api/pnap_network_api/models/__init__.py +++ b/pnap_network_api/pnap_network_api/models/__init__.py @@ -13,10 +13,10 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_network_api.models.asn_details import AsnDetails from pnap_network_api.models.bgp_ipv4_prefix import BgpIPv4Prefix +from pnap_network_api.models.bgp_ip_prefix import BgpIpPrefix from pnap_network_api.models.bgp_peer_group import BgpPeerGroup from pnap_network_api.models.bgp_peer_group_create import BgpPeerGroupCreate from pnap_network_api.models.bgp_peer_group_patch import BgpPeerGroupPatch @@ -31,3 +31,4 @@ from pnap_network_api.models.public_network_ip_block import PublicNetworkIpBlock from pnap_network_api.models.public_network_ip_block_create import PublicNetworkIpBlockCreate from pnap_network_api.models.public_network_modify import PublicNetworkModify + diff --git a/pnap_network_api/pnap_network_api/models/asn_details.py b/pnap_network_api/pnap_network_api/models/asn_details.py index ad4a5a87..450c5542 100644 --- a/pnap_network_api/pnap_network_api/models/asn_details.py +++ b/pnap_network_api/pnap_network_api/models/asn_details.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictInt, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class AsnDetails(BaseModel): """ @@ -38,11 +34,11 @@ class AsnDetails(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["asn", "isBringYourOwn", "verificationStatus", "verificationReason"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +51,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of AsnDetails from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,11 +66,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -85,7 +83,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of AsnDetails from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/bgp_ip_prefix.py b/pnap_network_api/pnap_network_api/models/bgp_ip_prefix.py new file mode 100644 index 00000000..b158b95a --- /dev/null +++ b/pnap_network_api/pnap_network_api/models/bgp_ip_prefix.py @@ -0,0 +1,107 @@ +# coding: utf-8 + +""" + Networks API + + Create, list, edit and delete public/private networks with the Network API. Use public networks to place multiple servers on the same network or VLAN. Assign new servers with IP addresses from the same CIDR range. Use private networks to avoid unnecessary egress data charges. Model your networks according to your business needs.

Helpful knowledge base articles are available for multi-private backend networks, public networks and border gateway protocol peer groups.

All URLs are relative to (https://api.phoenixnap.com/networks/v1/) + + The version of the OpenAPI document: 1.0 + Contact: support@phoenixnap.com + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class BgpIpPrefix(BaseModel): + """ + The BGP IP Prefix. + """ # noqa: E501 + ip_allocation_id: StrictStr = Field(description="IP allocation ID.", alias="ipAllocationId") + cidr: StrictStr = Field(description="The IP block in CIDR format, dependent on IP version.") + ip_version: StrictStr = Field(description="The IP block version.", alias="ipVersion") + status: StrictStr = Field(description="The BGP IP Prefix status. Can have one of the following values: `PENDING`, `BUSY`, `READY`, `ERROR` and `DELETING`.") + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["ipAllocationId", "cidr", "ipVersion", "status"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of BgpIpPrefix from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of BgpIpPrefix from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "ipAllocationId": obj.get("ipAllocationId"), + "cidr": obj.get("cidr"), + "ipVersion": obj.get("ipVersion"), + "status": obj.get("status") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/pnap_network_api/pnap_network_api/models/bgp_ipv4_prefix.py b/pnap_network_api/pnap_network_api/models/bgp_ipv4_prefix.py index 17f06c24..2e58648e 100644 --- a/pnap_network_api/pnap_network_api/models/bgp_ipv4_prefix.py +++ b/pnap_network_api/pnap_network_api/models/bgp_ipv4_prefix.py @@ -18,19 +18,15 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class BgpIPv4Prefix(BaseModel): """ - The BGP IPv4 Prefix. + The BGP IPv4 Prefix. Deprecated in favour of generic BgpIpPrefix. """ # noqa: E501 ipv4_allocation_id: StrictStr = Field(description="IPv4 allocation ID.", alias="ipv4AllocationId") cidr: Annotated[str, Field(strict=True)] = Field(description="The IP block in CIDR format.") @@ -47,11 +43,11 @@ def cidr_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(?:[1-9]|[1-2]\d|3[0-2])$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -64,7 +60,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of BgpIPv4Prefix from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -79,11 +75,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -94,7 +92,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of BgpIPv4Prefix from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/bgp_peer_group.py b/pnap_network_api/pnap_network_api/models/bgp_peer_group.py index 8daf94cf..ed62b05b 100644 --- a/pnap_network_api/pnap_network_api/models/bgp_peer_group.py +++ b/pnap_network_api/pnap_network_api/models/bgp_peer_group.py @@ -18,17 +18,14 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_network_api.models.asn_details import AsnDetails +from pnap_network_api.models.bgp_ip_prefix import BgpIpPrefix from pnap_network_api.models.bgp_ipv4_prefix import BgpIPv4Prefix -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class BgpPeerGroup(BaseModel): """ @@ -36,8 +33,9 @@ class BgpPeerGroup(BaseModel): """ # noqa: E501 id: StrictStr = Field(description="The unique identifier of the BGP Peer Group.") status: StrictStr = Field(description="The BGP Peer Group status. Can have one of the following values: `PENDING`, `ON_HOLD`, `BUSY`, `READY`, `ERROR`, `PENDING_DELETION` and `DELETING`.") - location: StrictStr = Field(description="The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`.") - ipv4_prefixes: List[BgpIPv4Prefix] = Field(description="The List of the BGP Peer Group IPv4 prefixes.", alias="ipv4Prefixes") + location: StrictStr = Field(description="The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`.") + ipv4_prefixes: List[BgpIPv4Prefix] = Field(description="The List of the BGP Peer Group IPv4 prefixes. Deprecated in favour of generic ipPrefixes.", alias="ipv4Prefixes") + ip_prefixes: List[BgpIpPrefix] = Field(description="The List of the BGP Peer Group IP prefixes.", alias="ipPrefixes") target_asn_details: AsnDetails = Field(alias="targetAsnDetails") active_asn_details: Optional[AsnDetails] = Field(default=None, alias="activeAsnDetails") password: Annotated[str, Field(min_length=8, strict=True, max_length=32)] = Field(description="The BGP Peer Group password.") @@ -45,12 +43,13 @@ class BgpPeerGroup(BaseModel): rpki_roa_origin_asn: StrictInt = Field(description="The RPKI ROA Origin ASN of the BGP Peer Group based on location.", alias="rpkiRoaOriginAsn") e_bgp_multi_hop: StrictInt = Field(description="The eBGP Multi-hop of the BGP Peer Group.", alias="eBgpMultiHop") peering_loopbacks_v4: List[Annotated[str, Field(strict=True)]] = Field(description="The IPv4 Peering Loopback addresses of the BGP Peer Group. Valid IP formats are IPv4 addresses.", alias="peeringLoopbacksV4") + peering_loopbacks_v6: List[StrictStr] = Field(description="The IPv6 Peering Loopback addresses of the BGP Peer Group. Valid IP formats are IPv6 addresses.", alias="peeringLoopbacksV6") keep_alive_timer_seconds: StrictInt = Field(description="The Keep Alive Timer in seconds of the BGP Peer Group.", alias="keepAliveTimerSeconds") hold_timer_seconds: StrictInt = Field(description="The Hold Timer in seconds of the BGP Peer Group.", alias="holdTimerSeconds") created_on: Optional[StrictStr] = Field(default=None, description="Date and time of creation.", alias="createdOn") last_updated_on: Optional[StrictStr] = Field(default=None, description="Date and time of last update.", alias="lastUpdatedOn") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["id", "status", "location", "ipv4Prefixes", "targetAsnDetails", "activeAsnDetails", "password", "advertisedRoutes", "rpkiRoaOriginAsn", "eBgpMultiHop", "peeringLoopbacksV4", "keepAliveTimerSeconds", "holdTimerSeconds", "createdOn", "lastUpdatedOn"] + __properties: ClassVar[List[str]] = ["id", "status", "location", "ipv4Prefixes", "ipPrefixes", "targetAsnDetails", "activeAsnDetails", "password", "advertisedRoutes", "rpkiRoaOriginAsn", "eBgpMultiHop", "peeringLoopbacksV4", "peeringLoopbacksV6", "keepAliveTimerSeconds", "holdTimerSeconds", "createdOn", "lastUpdatedOn"] @field_validator('password') def password_validate_regular_expression(cls, value): @@ -59,11 +58,11 @@ def password_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^[a-zA-Z0-9!@#$%^&*()\-|\[\]{}=;:<>,.]+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -76,7 +75,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of BgpPeerGroup from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -91,20 +90,29 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in ipv4_prefixes (list) _items = [] if self.ipv4_prefixes: - for _item in self.ipv4_prefixes: - if _item: - _items.append(_item.to_dict()) + for _item_ipv4_prefixes in self.ipv4_prefixes: + if _item_ipv4_prefixes: + _items.append(_item_ipv4_prefixes.to_dict()) _dict['ipv4Prefixes'] = _items + # override the default output from pydantic by calling `to_dict()` of each item in ip_prefixes (list) + _items = [] + if self.ip_prefixes: + for _item_ip_prefixes in self.ip_prefixes: + if _item_ip_prefixes: + _items.append(_item_ip_prefixes.to_dict()) + _dict['ipPrefixes'] = _items # override the default output from pydantic by calling `to_dict()` of target_asn_details if self.target_asn_details: _dict['targetAsnDetails'] = self.target_asn_details.to_dict() @@ -119,7 +127,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of BgpPeerGroup from a dict""" if obj is None: return None @@ -131,14 +139,16 @@ def from_dict(cls, obj: Dict) -> Self: "id": obj.get("id"), "status": obj.get("status"), "location": obj.get("location"), - "ipv4Prefixes": [BgpIPv4Prefix.from_dict(_item) for _item in obj.get("ipv4Prefixes")] if obj.get("ipv4Prefixes") is not None else None, - "targetAsnDetails": AsnDetails.from_dict(obj.get("targetAsnDetails")) if obj.get("targetAsnDetails") is not None else None, - "activeAsnDetails": AsnDetails.from_dict(obj.get("activeAsnDetails")) if obj.get("activeAsnDetails") is not None else None, + "ipv4Prefixes": [BgpIPv4Prefix.from_dict(_item) for _item in obj["ipv4Prefixes"]] if obj.get("ipv4Prefixes") is not None else None, + "ipPrefixes": [BgpIpPrefix.from_dict(_item) for _item in obj["ipPrefixes"]] if obj.get("ipPrefixes") is not None else None, + "targetAsnDetails": AsnDetails.from_dict(obj["targetAsnDetails"]) if obj.get("targetAsnDetails") is not None else None, + "activeAsnDetails": AsnDetails.from_dict(obj["activeAsnDetails"]) if obj.get("activeAsnDetails") is not None else None, "password": obj.get("password"), "advertisedRoutes": obj.get("advertisedRoutes"), "rpkiRoaOriginAsn": obj.get("rpkiRoaOriginAsn"), "eBgpMultiHop": obj.get("eBgpMultiHop"), "peeringLoopbacksV4": obj.get("peeringLoopbacksV4"), + "peeringLoopbacksV6": obj.get("peeringLoopbacksV6"), "keepAliveTimerSeconds": obj.get("keepAliveTimerSeconds"), "holdTimerSeconds": obj.get("holdTimerSeconds"), "createdOn": obj.get("createdOn"), diff --git a/pnap_network_api/pnap_network_api/models/bgp_peer_group_create.py b/pnap_network_api/pnap_network_api/models/bgp_peer_group_create.py index 0278117d..d4549b22 100644 --- a/pnap_network_api/pnap_network_api/models/bgp_peer_group_create.py +++ b/pnap_network_api/pnap_network_api/models/bgp_peer_group_create.py @@ -18,21 +18,17 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class BgpPeerGroupCreate(BaseModel): """ Create a BGP Peer Group. """ # noqa: E501 - location: StrictStr = Field(description="The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`.") + location: StrictStr = Field(description="The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`.") asn: StrictInt = Field(description="The BGP Peer Group ASN.") password: Optional[Annotated[str, Field(min_length=8, strict=True, max_length=32)]] = Field(default=None, description="The BGP Peer Group password.") advertised_routes: StrictStr = Field(description="The Advertised routes for the BGP Peer Group. Can have one of the following values: `DEFAULT` and `NONE`.", alias="advertisedRoutes") @@ -49,11 +45,11 @@ def password_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^[a-zA-Z0-9!@#$%^&*()\-|\[\]{}=;:<>,.]+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +62,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of BgpPeerGroupCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -81,11 +77,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -96,7 +94,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of BgpPeerGroupCreate from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/bgp_peer_group_patch.py b/pnap_network_api/pnap_network_api/models/bgp_peer_group_patch.py index 9d85fdc8..a7208250 100644 --- a/pnap_network_api/pnap_network_api/models/bgp_peer_group_patch.py +++ b/pnap_network_api/pnap_network_api/models/bgp_peer_group_patch.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class BgpPeerGroupPatch(BaseModel): """ @@ -48,11 +44,11 @@ def password_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^[a-zA-Z0-9!@#$%^&*()\-|\[\]{}=;:<>,.]+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -65,7 +61,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of BgpPeerGroupPatch from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -80,11 +76,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -95,7 +93,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of BgpPeerGroupPatch from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/error.py b/pnap_network_api/pnap_network_api/models/error.py index 276d1d0b..49f9e67c 100644 --- a/pnap_network_api/pnap_network_api/models/error.py +++ b/pnap_network_api/pnap_network_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/network_membership.py b/pnap_network_api/pnap_network_api/models/network_membership.py index c1ef1988..2e16c37d 100644 --- a/pnap_network_api/pnap_network_api/models/network_membership.py +++ b/pnap_network_api/pnap_network_api/models/network_membership.py @@ -18,30 +18,26 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class NetworkMembership(BaseModel): """ Resource details linked to the Network. """ # noqa: E501 resource_id: StrictStr = Field(description="The resource identifier.", alias="resourceId") - resource_type: StrictStr = Field(description="The resource's type.", alias="resourceType") + resource_type: StrictStr = Field(description="The resource's type. Can have one of the following values: `server`, `storage` or `virtual`.", alias="resourceType") ips: List[StrictStr] = Field(description="List of IPs associated to the resource.") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["resourceId", "resourceType", "ips"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of NetworkMembership from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of NetworkMembership from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/private_network.py b/pnap_network_api/pnap_network_api/models/private_network.py index 189c428a..1695f833 100644 --- a/pnap_network_api/pnap_network_api/models/private_network.py +++ b/pnap_network_api/pnap_network_api/models/private_network.py @@ -19,16 +19,13 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictInt, StrictStr -from pydantic import Field from typing_extensions import Annotated from pnap_network_api.models.network_membership import NetworkMembership from pnap_network_api.models.private_network_server import PrivateNetworkServer -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PrivateNetwork(BaseModel): """ @@ -49,11 +46,11 @@ class PrivateNetwork(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "name", "description", "vlanId", "type", "location", "locationDefault", "cidr", "servers", "memberships", "status", "createdOn"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +63,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PrivateNetwork from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -81,26 +78,28 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in servers (list) _items = [] if self.servers: - for _item in self.servers: - if _item: - _items.append(_item.to_dict()) + for _item_servers in self.servers: + if _item_servers: + _items.append(_item_servers.to_dict()) _dict['servers'] = _items # override the default output from pydantic by calling `to_dict()` of each item in memberships (list) _items = [] if self.memberships: - for _item in self.memberships: - if _item: - _items.append(_item.to_dict()) + for _item_memberships in self.memberships: + if _item_memberships: + _items.append(_item_memberships.to_dict()) _dict['memberships'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -110,7 +109,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PrivateNetwork from a dict""" if obj is None: return None @@ -127,8 +126,8 @@ def from_dict(cls, obj: Dict) -> Self: "location": obj.get("location"), "locationDefault": obj.get("locationDefault"), "cidr": obj.get("cidr"), - "servers": [PrivateNetworkServer.from_dict(_item) for _item in obj.get("servers")] if obj.get("servers") is not None else None, - "memberships": [NetworkMembership.from_dict(_item) for _item in obj.get("memberships")] if obj.get("memberships") is not None else None, + "servers": [PrivateNetworkServer.from_dict(_item) for _item in obj["servers"]] if obj.get("servers") is not None else None, + "memberships": [NetworkMembership.from_dict(_item) for _item in obj["memberships"]] if obj.get("memberships") is not None else None, "status": obj.get("status"), "createdOn": obj.get("createdOn") }) diff --git a/pnap_network_api/pnap_network_api/models/private_network_create.py b/pnap_network_api/pnap_network_api/models/private_network_create.py index e12a1fb0..74d48401 100644 --- a/pnap_network_api/pnap_network_api/models/private_network_create.py +++ b/pnap_network_api/pnap_network_api/models/private_network_create.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PrivateNetworkCreate(BaseModel): """ @@ -34,7 +30,7 @@ class PrivateNetworkCreate(BaseModel): """ # noqa: E501 name: Annotated[str, Field(min_length=1, strict=True, max_length=100)] = Field(description="The friendly name of this private network. This name should be unique.") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="The description of this private network.") - location: StrictStr = Field(description="The location of this private network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`.") + location: StrictStr = Field(description="The location of this private network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`.") location_default: Optional[StrictBool] = Field(default=False, description="Identifies network as the default private network for the specified location.", alias="locationDefault") vlan_id: Optional[Annotated[int, Field(le=4094, strict=True, ge=2)]] = Field(default=None, description="The VLAN that will be assigned to this network.", alias="vlanId") cidr: Optional[StrictStr] = Field(default=None, description="IP range associated with this private network in CIDR notation.
Setting the `force` query parameter to `true` allows you to skip assigning a specific IP range to network.") @@ -48,11 +44,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9(). -])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -65,7 +61,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PrivateNetworkCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -80,11 +76,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -95,7 +93,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PrivateNetworkCreate from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/private_network_modify.py b/pnap_network_api/pnap_network_api/models/private_network_modify.py index 46accd2b..0a98b7c8 100644 --- a/pnap_network_api/pnap_network_api/models/private_network_modify.py +++ b/pnap_network_api/pnap_network_api/models/private_network_modify.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PrivateNetworkModify(BaseModel): """ @@ -45,11 +41,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9(). -])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -62,7 +58,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PrivateNetworkModify from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -77,11 +73,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -92,7 +90,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PrivateNetworkModify from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/private_network_server.py b/pnap_network_api/pnap_network_api/models/private_network_server.py index ea907690..260599f9 100644 --- a/pnap_network_api/pnap_network_api/models/private_network_server.py +++ b/pnap_network_api/pnap_network_api/models/private_network_server.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PrivateNetworkServer(BaseModel): """ @@ -36,11 +32,11 @@ class PrivateNetworkServer(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "ips"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PrivateNetworkServer from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PrivateNetworkServer from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/public_network.py b/pnap_network_api/pnap_network_api/models/public_network.py index 4524e81e..2d902664 100644 --- a/pnap_network_api/pnap_network_api/models/public_network.py +++ b/pnap_network_api/pnap_network_api/models/public_network.py @@ -19,16 +19,13 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictInt, StrictStr -from pydantic import Field from typing_extensions import Annotated from pnap_network_api.models.network_membership import NetworkMembership from pnap_network_api.models.public_network_ip_block import PublicNetworkIpBlock -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PublicNetwork(BaseModel): """ @@ -38,7 +35,7 @@ class PublicNetwork(BaseModel): vlan_id: StrictInt = Field(description="The VLAN of this public network.", alias="vlanId") memberships: List[NetworkMembership] = Field(description="A list of resources that are members of this public network.") name: Annotated[str, Field(min_length=1, strict=True, max_length=100)] = Field(description="The friendly name of this public network.") - location: StrictStr = Field(description="The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`.") + location: StrictStr = Field(description="The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`.") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="The description of this public network.") status: StrictStr = Field(description="The status of the public network. Can have one of the following values: `BUSY`, `READY`, `DELETING` or `ERROR`.") created_on: datetime = Field(description="Date and time when this public network was created.", alias="createdOn") @@ -47,11 +44,11 @@ class PublicNetwork(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "vlanId", "memberships", "name", "location", "description", "status", "createdOn", "ipBlocks", "raEnabled"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -64,7 +61,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PublicNetwork from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -79,26 +76,28 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in memberships (list) _items = [] if self.memberships: - for _item in self.memberships: - if _item: - _items.append(_item.to_dict()) + for _item_memberships in self.memberships: + if _item_memberships: + _items.append(_item_memberships.to_dict()) _dict['memberships'] = _items # override the default output from pydantic by calling `to_dict()` of each item in ip_blocks (list) _items = [] if self.ip_blocks: - for _item in self.ip_blocks: - if _item: - _items.append(_item.to_dict()) + for _item_ip_blocks in self.ip_blocks: + if _item_ip_blocks: + _items.append(_item_ip_blocks.to_dict()) _dict['ipBlocks'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -108,7 +107,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PublicNetwork from a dict""" if obj is None: return None @@ -119,13 +118,13 @@ def from_dict(cls, obj: Dict) -> Self: _obj = cls.model_validate({ "id": obj.get("id"), "vlanId": obj.get("vlanId"), - "memberships": [NetworkMembership.from_dict(_item) for _item in obj.get("memberships")] if obj.get("memberships") is not None else None, + "memberships": [NetworkMembership.from_dict(_item) for _item in obj["memberships"]] if obj.get("memberships") is not None else None, "name": obj.get("name"), "location": obj.get("location"), "description": obj.get("description"), "status": obj.get("status"), "createdOn": obj.get("createdOn"), - "ipBlocks": [PublicNetworkIpBlock.from_dict(_item) for _item in obj.get("ipBlocks")] if obj.get("ipBlocks") is not None else None, + "ipBlocks": [PublicNetworkIpBlock.from_dict(_item) for _item in obj["ipBlocks"]] if obj.get("ipBlocks") is not None else None, "raEnabled": obj.get("raEnabled") }) # store additional fields in additional_properties diff --git a/pnap_network_api/pnap_network_api/models/public_network_create.py b/pnap_network_api/pnap_network_api/models/public_network_create.py index 4c308e1d..3062aa35 100644 --- a/pnap_network_api/pnap_network_api/models/public_network_create.py +++ b/pnap_network_api/pnap_network_api/models/public_network_create.py @@ -18,16 +18,12 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_network_api.models.public_network_ip_block_create import PublicNetworkIpBlockCreate -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PublicNetworkCreate(BaseModel): """ @@ -35,7 +31,7 @@ class PublicNetworkCreate(BaseModel): """ # noqa: E501 name: Annotated[str, Field(min_length=1, strict=True, max_length=100)] = Field(description="The friendly name of this public network. This name should be unique.") description: Optional[Annotated[str, Field(strict=True, max_length=250)]] = Field(default=None, description="The description of this public network.") - location: StrictStr = Field(description="The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`.") + location: StrictStr = Field(description="The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`.") vlan_id: Optional[Annotated[int, Field(le=4094, strict=True, ge=2)]] = Field(default=None, description="The VLAN that will be assigned to this network.", alias="vlanId") ip_blocks: Optional[Annotated[List[PublicNetworkIpBlockCreate], Field(max_length=11)]] = Field(default=None, description="A list of IP Blocks that will be associated with this public network. Supported maximum of 10 IPv4 Blocks and 1 IPv6 Block.", alias="ipBlocks") ra_enabled: Optional[StrictBool] = Field(default=None, description="Boolean indicating whether Router Advertisement is enabled. Only applicable for Network with IPv6 Blocks.", alias="raEnabled") @@ -49,11 +45,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9(). -])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +62,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PublicNetworkCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -81,19 +77,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in ip_blocks (list) _items = [] if self.ip_blocks: - for _item in self.ip_blocks: - if _item: - _items.append(_item.to_dict()) + for _item_ip_blocks in self.ip_blocks: + if _item_ip_blocks: + _items.append(_item_ip_blocks.to_dict()) _dict['ipBlocks'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -103,7 +101,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PublicNetworkCreate from a dict""" if obj is None: return None @@ -116,7 +114,7 @@ def from_dict(cls, obj: Dict) -> Self: "description": obj.get("description"), "location": obj.get("location"), "vlanId": obj.get("vlanId"), - "ipBlocks": [PublicNetworkIpBlockCreate.from_dict(_item) for _item in obj.get("ipBlocks")] if obj.get("ipBlocks") is not None else None, + "ipBlocks": [PublicNetworkIpBlockCreate.from_dict(_item) for _item in obj["ipBlocks"]] if obj.get("ipBlocks") is not None else None, "raEnabled": obj.get("raEnabled") }) # store additional fields in additional_properties diff --git a/pnap_network_api/pnap_network_api/models/public_network_ip_block.py b/pnap_network_api/pnap_network_api/models/public_network_ip_block.py index e9643caf..8ac090cf 100644 --- a/pnap_network_api/pnap_network_api/models/public_network_ip_block.py +++ b/pnap_network_api/pnap_network_api/models/public_network_ip_block.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PublicNetworkIpBlock(BaseModel): """ @@ -37,11 +33,11 @@ class PublicNetworkIpBlock(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "cidr", "usedIpsCount"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PublicNetworkIpBlock from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PublicNetworkIpBlock from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/public_network_ip_block_create.py b/pnap_network_api/pnap_network_api/models/public_network_ip_block_create.py index c9e44f94..ada33218 100644 --- a/pnap_network_api/pnap_network_api/models/public_network_ip_block_create.py +++ b/pnap_network_api/pnap_network_api/models/public_network_ip_block_create.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PublicNetworkIpBlockCreate(BaseModel): """ @@ -35,11 +31,11 @@ class PublicNetworkIpBlockCreate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +48,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PublicNetworkIpBlockCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +63,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -82,7 +80,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PublicNetworkIpBlockCreate from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/models/public_network_modify.py b/pnap_network_api/pnap_network_api/models/public_network_modify.py index 429c634d..3d405793 100644 --- a/pnap_network_api/pnap_network_api/models/public_network_modify.py +++ b/pnap_network_api/pnap_network_api/models/public_network_modify.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PublicNetworkModify(BaseModel): """ @@ -48,11 +44,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9(). -])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -65,7 +61,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PublicNetworkModify from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -80,11 +76,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -95,7 +93,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PublicNetworkModify from a dict""" if obj is None: return None diff --git a/pnap_network_api/pnap_network_api/rest.py b/pnap_network_api/pnap_network_api/rest.py index 3e1a79b9..45d47acb 100644 --- a/pnap_network_api/pnap_network_api/rest.py +++ b/pnap_network_api/pnap_network_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_network_api/pnap_network_api/version.py b/pnap_network_api/pnap_network_api/version.py index 2e42105e..5a135ffc 100644 --- a/pnap_network_api/pnap_network_api/version.py +++ b/pnap_network_api/pnap_network_api/version.py @@ -1 +1 @@ -VERSION = "3.0.1" \ No newline at end of file +VERSION = "3.1.0" \ No newline at end of file diff --git a/pnap_network_api/pyproject.toml b/pnap_network_api/pyproject.toml index a762b2f1..8e9624f0 100644 --- a/pnap_network_api/pyproject.toml +++ b/pnap_network_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_network_api" -version = "3.0.1" +version = "3.1.0" description = "Networks API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Networks API"] -include = ["pnap_network_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_network_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_network_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_network_api/requirements.txt b/pnap_network_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_network_api/requirements.txt +++ b/pnap_network_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_network_api/setup.py b/pnap_network_api/setup.py index 3e4687e8..818f9029 100644 --- a/pnap_network_api/setup.py +++ b/pnap_network_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Networks API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_network_api" -VERSION = "3.0.1" -PYTHON_REQUIRES = ">=3.7" +VERSION = "3.1.0" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ Create, list, edit and delete public/private networks with the Network API. Use public networks to place multiple servers on the same network or VLAN. Assign new servers with IP addresses from the same CIDR range. Use private networks to avoid unnecessary egress data charges. Model your networks according to your business needs.<br> <br> <span class='pnap-api-knowledge-base-link'> Helpful knowledge base articles are available for <a href='https://phoenixnap.com/kb/bmc-server-management-via-api#multi-private-backend-network-api' target='_blank'>multi-private backend networks</a>, <a href='https://phoenixnap.com/kb/bmc-server-management-via-api#ftoc-heading-15' target='_blank'>public networks</a> and <a href='https://phoenixnap.com/kb/border-gateway-protocol-bmc' target='_blank'>border gateway protocol peer groups</a>. </span><br> <br> <b>All URLs are relative to (https://api.phoenixnap.com/networks/v1/)</b> """, # noqa: E501 package_data={"pnap_network_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_network_storage_api/README.md b/pnap_network_storage_api/README.md index a943d166..bc250b17 100644 --- a/pnap_network_storage_api/README.md +++ b/pnap_network_storage_api/README.md @@ -12,13 +12,13 @@ Knowledge base articles to help you can be found This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0 -- Package version: 2.0.4 +- Package version: 2.0.5 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -48,9 +48,16 @@ Then import the package: import pnap_network_storage_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_network_storage_api from pnap_network_storage_api.rest import ApiException from pprint import pprint @@ -101,6 +108,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -162,4 +170,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_network_storage_api/docs/Error.md b/pnap_network_storage_api/docs/Error.md index 4df161a6..fff202d2 100644 --- a/pnap_network_storage_api/docs/Error.md +++ b/pnap_network_storage_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/NfsPermissions.md b/pnap_network_storage_api/docs/NfsPermissions.md index 0ac234b0..5a5868d7 100644 --- a/pnap_network_storage_api/docs/NfsPermissions.md +++ b/pnap_network_storage_api/docs/NfsPermissions.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of NfsPermissions from a JSON string nfs_permissions_instance = NfsPermissions.from_json(json) # print the JSON string representation of the object -print NfsPermissions.to_json() +print(NfsPermissions.to_json()) # convert the object into a dict nfs_permissions_dict = nfs_permissions_instance.to_dict() # create an instance of NfsPermissions from a dict -nfs_permissions_form_dict = nfs_permissions.from_dict(nfs_permissions_dict) +nfs_permissions_from_dict = NfsPermissions.from_dict(nfs_permissions_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/NfsPermissionsCreate.md b/pnap_network_storage_api/docs/NfsPermissionsCreate.md index 65683372..281f8667 100644 --- a/pnap_network_storage_api/docs/NfsPermissionsCreate.md +++ b/pnap_network_storage_api/docs/NfsPermissionsCreate.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of NfsPermissionsCreate from a JSON string nfs_permissions_create_instance = NfsPermissionsCreate.from_json(json) # print the JSON string representation of the object -print NfsPermissionsCreate.to_json() +print(NfsPermissionsCreate.to_json()) # convert the object into a dict nfs_permissions_create_dict = nfs_permissions_create_instance.to_dict() # create an instance of NfsPermissionsCreate from a dict -nfs_permissions_create_form_dict = nfs_permissions_create.from_dict(nfs_permissions_create_dict) +nfs_permissions_create_from_dict = NfsPermissionsCreate.from_dict(nfs_permissions_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/NfsPermissionsUpdate.md b/pnap_network_storage_api/docs/NfsPermissionsUpdate.md index 7cf1d392..5e34e078 100644 --- a/pnap_network_storage_api/docs/NfsPermissionsUpdate.md +++ b/pnap_network_storage_api/docs/NfsPermissionsUpdate.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of NfsPermissionsUpdate from a JSON string nfs_permissions_update_instance = NfsPermissionsUpdate.from_json(json) # print the JSON string representation of the object -print NfsPermissionsUpdate.to_json() +print(NfsPermissionsUpdate.to_json()) # convert the object into a dict nfs_permissions_update_dict = nfs_permissions_update_instance.to_dict() # create an instance of NfsPermissionsUpdate from a dict -nfs_permissions_update_form_dict = nfs_permissions_update.from_dict(nfs_permissions_update_dict) +nfs_permissions_update_from_dict = NfsPermissionsUpdate.from_dict(nfs_permissions_update_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/Permissions.md b/pnap_network_storage_api/docs/Permissions.md index 87022b8d..47dbb660 100644 --- a/pnap_network_storage_api/docs/Permissions.md +++ b/pnap_network_storage_api/docs/Permissions.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Permissions from a JSON string permissions_instance = Permissions.from_json(json) # print the JSON string representation of the object -print Permissions.to_json() +print(Permissions.to_json()) # convert the object into a dict permissions_dict = permissions_instance.to_dict() # create an instance of Permissions from a dict -permissions_form_dict = permissions.from_dict(permissions_dict) +permissions_from_dict = Permissions.from_dict(permissions_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/PermissionsCreate.md b/pnap_network_storage_api/docs/PermissionsCreate.md index b1979274..87e35fd1 100644 --- a/pnap_network_storage_api/docs/PermissionsCreate.md +++ b/pnap_network_storage_api/docs/PermissionsCreate.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of PermissionsCreate from a JSON string permissions_create_instance = PermissionsCreate.from_json(json) # print the JSON string representation of the object -print PermissionsCreate.to_json() +print(PermissionsCreate.to_json()) # convert the object into a dict permissions_create_dict = permissions_create_instance.to_dict() # create an instance of PermissionsCreate from a dict -permissions_create_form_dict = permissions_create.from_dict(permissions_create_dict) +permissions_create_from_dict = PermissionsCreate.from_dict(permissions_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/PermissionsUpdate.md b/pnap_network_storage_api/docs/PermissionsUpdate.md index ff86648e..695985d9 100644 --- a/pnap_network_storage_api/docs/PermissionsUpdate.md +++ b/pnap_network_storage_api/docs/PermissionsUpdate.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of PermissionsUpdate from a JSON string permissions_update_instance = PermissionsUpdate.from_json(json) # print the JSON string representation of the object -print PermissionsUpdate.to_json() +print(PermissionsUpdate.to_json()) # convert the object into a dict permissions_update_dict = permissions_update_instance.to_dict() # create an instance of PermissionsUpdate from a dict -permissions_update_form_dict = permissions_update.from_dict(permissions_update_dict) +permissions_update_from_dict = PermissionsUpdate.from_dict(permissions_update_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/Status.md b/pnap_network_storage_api/docs/Status.md index 6ee02505..1f3f282c 100644 --- a/pnap_network_storage_api/docs/Status.md +++ b/pnap_network_storage_api/docs/Status.md @@ -2,10 +2,15 @@ Status of the resource. Currently this field should be set to `READY`, `BUSY`, `DELETING` or `ERROR`. -## Properties +## Enum -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- +* `READY` (value: `'READY'`) + +* `BUSY` (value: `'BUSY'`) + +* `DELETING` (value: `'DELETING'`) + +* `ERROR` (value: `'ERROR'`) [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/StorageNetwork.md b/pnap_network_storage_api/docs/StorageNetwork.md index 0242f9a0..03030e7f 100644 --- a/pnap_network_storage_api/docs/StorageNetwork.md +++ b/pnap_network_storage_api/docs/StorageNetwork.md @@ -27,12 +27,12 @@ json = "{}" # create an instance of StorageNetwork from a JSON string storage_network_instance = StorageNetwork.from_json(json) # print the JSON string representation of the object -print StorageNetwork.to_json() +print(StorageNetwork.to_json()) # convert the object into a dict storage_network_dict = storage_network_instance.to_dict() # create an instance of StorageNetwork from a dict -storage_network_form_dict = storage_network.from_dict(storage_network_dict) +storage_network_from_dict = StorageNetwork.from_dict(storage_network_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/StorageNetworkCreate.md b/pnap_network_storage_api/docs/StorageNetworkCreate.md index 1ff9336a..45935fd1 100644 --- a/pnap_network_storage_api/docs/StorageNetworkCreate.md +++ b/pnap_network_storage_api/docs/StorageNetworkCreate.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of StorageNetworkCreate from a JSON string storage_network_create_instance = StorageNetworkCreate.from_json(json) # print the JSON string representation of the object -print StorageNetworkCreate.to_json() +print(StorageNetworkCreate.to_json()) # convert the object into a dict storage_network_create_dict = storage_network_create_instance.to_dict() # create an instance of StorageNetworkCreate from a dict -storage_network_create_form_dict = storage_network_create.from_dict(storage_network_create_dict) +storage_network_create_from_dict = StorageNetworkCreate.from_dict(storage_network_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/StorageNetworkUpdate.md b/pnap_network_storage_api/docs/StorageNetworkUpdate.md index e066bd84..c38416a5 100644 --- a/pnap_network_storage_api/docs/StorageNetworkUpdate.md +++ b/pnap_network_storage_api/docs/StorageNetworkUpdate.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of StorageNetworkUpdate from a JSON string storage_network_update_instance = StorageNetworkUpdate.from_json(json) # print the JSON string representation of the object -print StorageNetworkUpdate.to_json() +print(StorageNetworkUpdate.to_json()) # convert the object into a dict storage_network_update_dict = storage_network_update_instance.to_dict() # create an instance of StorageNetworkUpdate from a dict -storage_network_update_form_dict = storage_network_update.from_dict(storage_network_update_dict) +storage_network_update_from_dict = StorageNetworkUpdate.from_dict(storage_network_update_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/StorageNetworkVolumeCreate.md b/pnap_network_storage_api/docs/StorageNetworkVolumeCreate.md index 171fc0e5..5f554244 100644 --- a/pnap_network_storage_api/docs/StorageNetworkVolumeCreate.md +++ b/pnap_network_storage_api/docs/StorageNetworkVolumeCreate.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of StorageNetworkVolumeCreate from a JSON string storage_network_volume_create_instance = StorageNetworkVolumeCreate.from_json(json) # print the JSON string representation of the object -print StorageNetworkVolumeCreate.to_json() +print(StorageNetworkVolumeCreate.to_json()) # convert the object into a dict storage_network_volume_create_dict = storage_network_volume_create_instance.to_dict() # create an instance of StorageNetworkVolumeCreate from a dict -storage_network_volume_create_form_dict = storage_network_volume_create.from_dict(storage_network_volume_create_dict) +storage_network_volume_create_from_dict = StorageNetworkVolumeCreate.from_dict(storage_network_volume_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/StorageNetworksApi.md b/pnap_network_storage_api/docs/StorageNetworksApi.md index 6fc0f911..e2fc26eb 100644 --- a/pnap_network_storage_api/docs/StorageNetworksApi.md +++ b/pnap_network_storage_api/docs/StorageNetworksApi.md @@ -29,8 +29,6 @@ List all storage networks. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.storage_network import StorageNetwork from pnap_network_storage_api.rest import ApiException @@ -110,8 +108,6 @@ Delete a storage network and its volume. A storage network can only be removed i * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.rest import ApiException from pprint import pprint @@ -190,8 +186,6 @@ Get storage network details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.storage_network import StorageNetwork from pnap_network_storage_api.rest import ApiException @@ -270,8 +264,6 @@ Update storage network details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.storage_network import StorageNetwork from pnap_network_storage_api.models.storage_network_update import StorageNetworkUpdate @@ -354,8 +346,6 @@ Create a storage network and volume. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.storage_network import StorageNetwork from pnap_network_storage_api.models.storage_network_create import StorageNetworkCreate @@ -437,8 +427,6 @@ Display one or more volumes belonging to a storage network. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.volume import Volume from pnap_network_storage_api.rest import ApiException @@ -519,8 +507,6 @@ Create a volume belonging to a storage network. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.volume import Volume from pnap_network_storage_api.models.volume_create import VolumeCreate @@ -605,8 +591,6 @@ Delete a Storage Network's Volume * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.rest import ApiException from pprint import pprint @@ -686,8 +670,6 @@ Get a storage network's volume details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.volume import Volume from pnap_network_storage_api.rest import ApiException @@ -768,8 +750,6 @@ Update a storage network's volume details. Volume's capacity requested cannot be * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.volume import Volume from pnap_network_storage_api.models.volume_update import VolumeUpdate @@ -857,8 +837,6 @@ Overwrites tags assigned for the volume. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_network_storage_api from pnap_network_storage_api.models.tag_assignment_request import TagAssignmentRequest from pnap_network_storage_api.models.volume import Volume diff --git a/pnap_network_storage_api/docs/TagAssignment.md b/pnap_network_storage_api/docs/TagAssignment.md index 5e7cc6dd..d1dd86cd 100644 --- a/pnap_network_storage_api/docs/TagAssignment.md +++ b/pnap_network_storage_api/docs/TagAssignment.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of TagAssignment from a JSON string tag_assignment_instance = TagAssignment.from_json(json) # print the JSON string representation of the object -print TagAssignment.to_json() +print(TagAssignment.to_json()) # convert the object into a dict tag_assignment_dict = tag_assignment_instance.to_dict() # create an instance of TagAssignment from a dict -tag_assignment_form_dict = tag_assignment.from_dict(tag_assignment_dict) +tag_assignment_from_dict = TagAssignment.from_dict(tag_assignment_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/TagAssignmentRequest.md b/pnap_network_storage_api/docs/TagAssignmentRequest.md index 74abfa31..afa13042 100644 --- a/pnap_network_storage_api/docs/TagAssignmentRequest.md +++ b/pnap_network_storage_api/docs/TagAssignmentRequest.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of TagAssignmentRequest from a JSON string tag_assignment_request_instance = TagAssignmentRequest.from_json(json) # print the JSON string representation of the object -print TagAssignmentRequest.to_json() +print(TagAssignmentRequest.to_json()) # convert the object into a dict tag_assignment_request_dict = tag_assignment_request_instance.to_dict() # create an instance of TagAssignmentRequest from a dict -tag_assignment_request_form_dict = tag_assignment_request.from_dict(tag_assignment_request_dict) +tag_assignment_request_from_dict = TagAssignmentRequest.from_dict(tag_assignment_request_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/Volume.md b/pnap_network_storage_api/docs/Volume.md index 7d4e407c..32e3d712 100644 --- a/pnap_network_storage_api/docs/Volume.md +++ b/pnap_network_storage_api/docs/Volume.md @@ -30,12 +30,12 @@ json = "{}" # create an instance of Volume from a JSON string volume_instance = Volume.from_json(json) # print the JSON string representation of the object -print Volume.to_json() +print(Volume.to_json()) # convert the object into a dict volume_dict = volume_instance.to_dict() # create an instance of Volume from a dict -volume_form_dict = volume.from_dict(volume_dict) +volume_from_dict = Volume.from_dict(volume_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/VolumeCreate.md b/pnap_network_storage_api/docs/VolumeCreate.md index 3299a193..ba28f590 100644 --- a/pnap_network_storage_api/docs/VolumeCreate.md +++ b/pnap_network_storage_api/docs/VolumeCreate.md @@ -23,12 +23,12 @@ json = "{}" # create an instance of VolumeCreate from a JSON string volume_create_instance = VolumeCreate.from_json(json) # print the JSON string representation of the object -print VolumeCreate.to_json() +print(VolumeCreate.to_json()) # convert the object into a dict volume_create_dict = volume_create_instance.to_dict() # create an instance of VolumeCreate from a dict -volume_create_form_dict = volume_create.from_dict(volume_create_dict) +volume_create_from_dict = VolumeCreate.from_dict(volume_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/docs/VolumeUpdate.md b/pnap_network_storage_api/docs/VolumeUpdate.md index eeb82bbf..1a39eb17 100644 --- a/pnap_network_storage_api/docs/VolumeUpdate.md +++ b/pnap_network_storage_api/docs/VolumeUpdate.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of VolumeUpdate from a JSON string volume_update_instance = VolumeUpdate.from_json(json) # print the JSON string representation of the object -print VolumeUpdate.to_json() +print(VolumeUpdate.to_json()) # convert the object into a dict volume_update_dict = volume_update_instance.to_dict() # create an instance of VolumeUpdate from a dict -volume_update_form_dict = volume_update.from_dict(volume_update_dict) +volume_update_from_dict = VolumeUpdate.from_dict(volume_update_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_network_storage_api/pnap_network_storage_api/__init__.py b/pnap_network_storage_api/pnap_network_storage_api/__init__.py index b41c924b..e66c1ec3 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/__init__.py +++ b/pnap_network_storage_api/pnap_network_storage_api/__init__.py @@ -15,37 +15,69 @@ """ # noqa: E501 -__version__ = "2.0.4" +__version__ = "2.0.5" + +# Define package exports +__all__ = [ + "StorageNetworksApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "Error", + "NfsPermissions", + "NfsPermissionsCreate", + "NfsPermissionsUpdate", + "Permissions", + "PermissionsCreate", + "PermissionsUpdate", + "Status", + "StorageNetwork", + "StorageNetworkCreate", + "StorageNetworkUpdate", + "StorageNetworkVolumeCreate", + "TagAssignment", + "TagAssignmentRequest", + "Volume", + "VolumeCreate", + "VolumeUpdate", +] # import apis into sdk package -from pnap_network_storage_api.api.storage_networks_api import StorageNetworksApi +from pnap_network_storage_api.api.storage_networks_api import StorageNetworksApi as StorageNetworksApi # import ApiClient -from pnap_network_storage_api.api_response import ApiResponse -from pnap_network_storage_api.api_client import ApiClient -from pnap_network_storage_api.configuration import Configuration -from pnap_network_storage_api.exceptions import OpenApiException -from pnap_network_storage_api.exceptions import ApiTypeError -from pnap_network_storage_api.exceptions import ApiValueError -from pnap_network_storage_api.exceptions import ApiKeyError -from pnap_network_storage_api.exceptions import ApiAttributeError -from pnap_network_storage_api.exceptions import ApiException +from pnap_network_storage_api.api_response import ApiResponse as ApiResponse +from pnap_network_storage_api.api_client import ApiClient as ApiClient +from pnap_network_storage_api.configuration import Configuration as Configuration +from pnap_network_storage_api.exceptions import OpenApiException as OpenApiException +from pnap_network_storage_api.exceptions import ApiTypeError as ApiTypeError +from pnap_network_storage_api.exceptions import ApiValueError as ApiValueError +from pnap_network_storage_api.exceptions import ApiKeyError as ApiKeyError +from pnap_network_storage_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_network_storage_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_network_storage_api.models.error import Error -from pnap_network_storage_api.models.nfs_permissions import NfsPermissions -from pnap_network_storage_api.models.nfs_permissions_create import NfsPermissionsCreate -from pnap_network_storage_api.models.nfs_permissions_update import NfsPermissionsUpdate -from pnap_network_storage_api.models.permissions import Permissions -from pnap_network_storage_api.models.permissions_create import PermissionsCreate -from pnap_network_storage_api.models.permissions_update import PermissionsUpdate -from pnap_network_storage_api.models.status import Status -from pnap_network_storage_api.models.storage_network import StorageNetwork -from pnap_network_storage_api.models.storage_network_create import StorageNetworkCreate -from pnap_network_storage_api.models.storage_network_update import StorageNetworkUpdate -from pnap_network_storage_api.models.storage_network_volume_create import StorageNetworkVolumeCreate -from pnap_network_storage_api.models.tag_assignment import TagAssignment -from pnap_network_storage_api.models.tag_assignment_request import TagAssignmentRequest -from pnap_network_storage_api.models.volume import Volume -from pnap_network_storage_api.models.volume_create import VolumeCreate -from pnap_network_storage_api.models.volume_update import VolumeUpdate +from pnap_network_storage_api.models.error import Error as Error +from pnap_network_storage_api.models.nfs_permissions import NfsPermissions as NfsPermissions +from pnap_network_storage_api.models.nfs_permissions_create import NfsPermissionsCreate as NfsPermissionsCreate +from pnap_network_storage_api.models.nfs_permissions_update import NfsPermissionsUpdate as NfsPermissionsUpdate +from pnap_network_storage_api.models.permissions import Permissions as Permissions +from pnap_network_storage_api.models.permissions_create import PermissionsCreate as PermissionsCreate +from pnap_network_storage_api.models.permissions_update import PermissionsUpdate as PermissionsUpdate +from pnap_network_storage_api.models.status import Status as Status +from pnap_network_storage_api.models.storage_network import StorageNetwork as StorageNetwork +from pnap_network_storage_api.models.storage_network_create import StorageNetworkCreate as StorageNetworkCreate +from pnap_network_storage_api.models.storage_network_update import StorageNetworkUpdate as StorageNetworkUpdate +from pnap_network_storage_api.models.storage_network_volume_create import StorageNetworkVolumeCreate as StorageNetworkVolumeCreate +from pnap_network_storage_api.models.tag_assignment import TagAssignment as TagAssignment +from pnap_network_storage_api.models.tag_assignment_request import TagAssignmentRequest as TagAssignmentRequest +from pnap_network_storage_api.models.volume import Volume as Volume +from pnap_network_storage_api.models.volume_create import VolumeCreate as VolumeCreate +from pnap_network_storage_api.models.volume_update import VolumeUpdate as VolumeUpdate + diff --git a/pnap_network_storage_api/pnap_network_storage_api/api/storage_networks_api.py b/pnap_network_storage_api/pnap_network_storage_api/api/storage_networks_api.py index 5f439bef..888ceffa 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/api/storage_networks_api.py +++ b/pnap_network_storage_api/pnap_network_storage_api/api/storage_networks_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Network Storage API @@ -13,23 +11,14 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictStr +from pydantic import Field, StrictStr from typing import List, Optional - +from typing_extensions import Annotated from pnap_network_storage_api.models.storage_network import StorageNetwork from pnap_network_storage_api.models.storage_network_create import StorageNetworkCreate from pnap_network_storage_api.models.storage_network_update import StorageNetworkUpdate @@ -38,7 +27,7 @@ from pnap_network_storage_api.models.volume_create import VolumeCreate from pnap_network_storage_api.models.volume_update import VolumeUpdate -from pnap_network_storage_api.api_client import ApiClient +from pnap_network_storage_api.api_client import ApiClient, RequestSerialized from pnap_network_storage_api.api_response import ApiResponse from pnap_network_storage_api.rest import RESTResponseType @@ -272,7 +261,7 @@ def _storage_networks_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -283,7 +272,9 @@ def _storage_networks_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -298,11 +289,12 @@ def _storage_networks_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -550,7 +542,7 @@ def _storage_networks_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -561,7 +553,9 @@ def _storage_networks_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -574,11 +568,12 @@ def _storage_networks_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -817,7 +812,7 @@ def _storage_networks_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -828,7 +823,9 @@ def _storage_networks_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -841,11 +838,12 @@ def _storage_networks_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1100,7 +1098,7 @@ def _storage_networks_id_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1111,7 +1109,9 @@ def _storage_networks_id_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1126,11 +1126,12 @@ def _storage_networks_id_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1388,7 +1389,7 @@ def _storage_networks_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1399,7 +1400,9 @@ def _storage_networks_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1412,11 +1415,12 @@ def _storage_networks_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -1681,7 +1685,7 @@ def _storage_networks_storage_network_id_volumes_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1693,7 +1697,9 @@ def _storage_networks_storage_network_id_volumes_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1710,11 +1716,12 @@ def _storage_networks_storage_network_id_volumes_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1975,7 +1982,7 @@ def _storage_networks_storage_network_id_volumes_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1986,7 +1993,9 @@ def _storage_networks_storage_network_id_volumes_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2001,11 +2010,12 @@ def _storage_networks_storage_network_id_volumes_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -2276,7 +2286,7 @@ def _storage_networks_storage_network_id_volumes_volume_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2287,7 +2297,9 @@ def _storage_networks_storage_network_id_volumes_volume_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2302,11 +2314,12 @@ def _storage_networks_storage_network_id_volumes_volume_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -2558,7 +2571,7 @@ def _storage_networks_storage_network_id_volumes_volume_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2569,7 +2582,9 @@ def _storage_networks_storage_network_id_volumes_volume_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2584,11 +2599,12 @@ def _storage_networks_storage_network_id_volumes_volume_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -2865,7 +2881,7 @@ def _storage_networks_storage_network_id_volumes_volume_id_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -2876,7 +2892,9 @@ def _storage_networks_storage_network_id_volumes_volume_id_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -2893,11 +2911,12 @@ def _storage_networks_storage_network_id_volumes_volume_id_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -3181,7 +3200,7 @@ def _storage_networks_storage_network_id_volumes_volume_id_tags_put_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -3193,7 +3212,9 @@ def _storage_networks_storage_network_id_volumes_volume_id_tags_put_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -3210,11 +3231,12 @@ def _storage_networks_storage_network_id_volumes_volume_id_tags_put_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_network_storage_api/pnap_network_storage_api/api_client.py b/pnap_network_storage_api/pnap_network_storage_api/api_client.py index 67661439..1eb48ed1 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/api_client.py +++ b/pnap_network_storage_api/pnap_network_storage_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Network Storage API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_network_storage_api.configuration import Configuration -from pnap_network_storage_api.api_response import ApiResponse +from pnap_network_storage_api.api_response import ApiResponse, T as ApiResponseT import pnap_network_storage_api.models from pnap_network_storage_api import rest from pnap_network_storage_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_network_storage_api/2.0.4" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_network_storage_api/2.0.5" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_network_storage_api/2.0.4" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_network_storage_api/2.0.5" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_network_storage_api/pnap_network_storage_api/api_response.py b/pnap_network_storage_api/pnap_network_storage_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/api_response.py +++ b/pnap_network_storage_api/pnap_network_storage_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_network_storage_api/pnap_network_storage_api/configuration.py b/pnap_network_storage_api/pnap_network_storage_api/configuration.py index a1961105..1e8bcaea 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/configuration.py +++ b/pnap_network_storage_api/pnap_network_storage_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Network Storage API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/network-storage/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0\n"\ - "SDK Package Version: 2.0.4".\ + "SDK Package Version: 2.0.5".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_network_storage_api/pnap_network_storage_api/exceptions.py b/pnap_network_storage_api/pnap_network_storage_api/exceptions.py index 65cb0a4e..ea2a3cca 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/exceptions.py +++ b/pnap_network_storage_api/pnap_network_storage_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Network Storage API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/__init__.py b/pnap_network_storage_api/pnap_network_storage_api/models/__init__.py index b45696ea..65f884ec 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/__init__.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_network_storage_api.models.error import Error from pnap_network_storage_api.models.nfs_permissions import NfsPermissions @@ -32,3 +31,4 @@ from pnap_network_storage_api.models.volume import Volume from pnap_network_storage_api.models.volume_create import VolumeCreate from pnap_network_storage_api.models.volume_update import VolumeUpdate + diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/error.py b/pnap_network_storage_api/pnap_network_storage_api/models/error.py index a632475d..c64d255d 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/error.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions.py b/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions.py index 76a0916f..8f66aafc 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class NfsPermissions(BaseModel): """ @@ -39,11 +35,11 @@ class NfsPermissions(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["readWrite", "readOnly", "rootSquash", "noSquash", "allSquash"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -56,7 +52,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of NfsPermissions from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -71,11 +67,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -86,7 +84,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of NfsPermissions from a dict""" if obj is None: return None diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_create.py b/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_create.py index 00c607a4..260a016d 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_create.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_create.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class NfsPermissionsCreate(BaseModel): """ @@ -40,11 +36,11 @@ class NfsPermissionsCreate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["readWrite", "readOnly", "rootSquash", "noSquash", "allSquash"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -57,7 +53,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of NfsPermissionsCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -72,11 +68,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of NfsPermissionsCreate from a dict""" if obj is None: return None diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_update.py b/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_update.py index 35426e4e..7785ac83 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_update.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/nfs_permissions_update.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class NfsPermissionsUpdate(BaseModel): """ @@ -40,11 +36,11 @@ class NfsPermissionsUpdate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["readWrite", "readOnly", "rootSquash", "noSquash", "allSquash"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -57,7 +53,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of NfsPermissionsUpdate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -72,11 +68,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of NfsPermissionsUpdate from a dict""" if obj is None: return None diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/permissions.py b/pnap_network_storage_api/pnap_network_storage_api/models/permissions.py index 039369fe..ec80ac39 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/permissions.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/permissions.py @@ -18,14 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel from pnap_network_storage_api.models.nfs_permissions import NfsPermissions -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Permissions(BaseModel): """ @@ -35,11 +32,11 @@ class Permissions(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["nfs"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Permissions from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of nfs @@ -85,7 +84,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Permissions from a dict""" if obj is None: return None @@ -94,7 +93,7 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "nfs": NfsPermissions.from_dict(obj.get("nfs")) if obj.get("nfs") is not None else None + "nfs": NfsPermissions.from_dict(obj["nfs"]) if obj.get("nfs") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/permissions_create.py b/pnap_network_storage_api/pnap_network_storage_api/models/permissions_create.py index 04f5f973..611dad18 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/permissions_create.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/permissions_create.py @@ -18,14 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel from pnap_network_storage_api.models.nfs_permissions_create import NfsPermissionsCreate -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PermissionsCreate(BaseModel): """ @@ -35,11 +32,11 @@ class PermissionsCreate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["nfs"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PermissionsCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of nfs @@ -85,7 +84,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PermissionsCreate from a dict""" if obj is None: return None @@ -94,7 +93,7 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "nfs": NfsPermissionsCreate.from_dict(obj.get("nfs")) if obj.get("nfs") is not None else None + "nfs": NfsPermissionsCreate.from_dict(obj["nfs"]) if obj.get("nfs") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/permissions_update.py b/pnap_network_storage_api/pnap_network_storage_api/models/permissions_update.py index b295ee59..997e6c8b 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/permissions_update.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/permissions_update.py @@ -18,14 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel from pnap_network_storage_api.models.nfs_permissions_update import NfsPermissionsUpdate -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PermissionsUpdate(BaseModel): """ @@ -35,11 +32,11 @@ class PermissionsUpdate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["nfs"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PermissionsUpdate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of nfs @@ -85,7 +84,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PermissionsUpdate from a dict""" if obj is None: return None @@ -94,7 +93,7 @@ def from_dict(cls, obj: Dict) -> Self: return cls.model_validate(obj) _obj = cls.model_validate({ - "nfs": NfsPermissionsUpdate.from_dict(obj.get("nfs")) if obj.get("nfs") is not None else None + "nfs": NfsPermissionsUpdate.from_dict(obj["nfs"]) if obj.get("nfs") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/status.py b/pnap_network_storage_api/pnap_network_storage_api/models/status.py index 559c1ab5..1dcb188b 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/status.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/status.py @@ -15,16 +15,8 @@ from __future__ import annotations import json -import pprint -import re # noqa: F401 from enum import Enum - - - -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing_extensions import Self class Status(str, Enum): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network.py b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network.py index a9fb686b..c02f06dd 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network.py @@ -19,15 +19,12 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from pnap_network_storage_api.models.status import Status from pnap_network_storage_api.models.volume import Volume -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class StorageNetwork(BaseModel): """ @@ -46,11 +43,11 @@ class StorageNetwork(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "name", "description", "status", "location", "networkId", "ips", "createdOn", "deleteRequestedOn", "volumes"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -63,7 +60,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of StorageNetwork from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -78,19 +75,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in volumes (list) _items = [] if self.volumes: - for _item in self.volumes: - if _item: - _items.append(_item.to_dict()) + for _item_volumes in self.volumes: + if _item_volumes: + _items.append(_item_volumes.to_dict()) _dict['volumes'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -100,7 +99,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of StorageNetwork from a dict""" if obj is None: return None @@ -118,7 +117,7 @@ def from_dict(cls, obj: Dict) -> Self: "ips": obj.get("ips"), "createdOn": obj.get("createdOn"), "deleteRequestedOn": obj.get("deleteRequestedOn"), - "volumes": [Volume.from_dict(_item) for _item in obj.get("volumes")] if obj.get("volumes") is not None else None + "volumes": [Volume.from_dict(_item) for _item in obj["volumes"]] if obj.get("volumes") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_create.py b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_create.py index 29bb5465..ea489b32 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_create.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_create.py @@ -18,16 +18,12 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_network_storage_api.models.storage_network_volume_create import StorageNetworkVolumeCreate -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class StorageNetworkCreate(BaseModel): """ @@ -48,11 +44,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9(). -])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -65,7 +61,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of StorageNetworkCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -80,19 +76,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in volumes (list) _items = [] if self.volumes: - for _item in self.volumes: - if _item: - _items.append(_item.to_dict()) + for _item_volumes in self.volumes: + if _item_volumes: + _items.append(_item_volumes.to_dict()) _dict['volumes'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -102,7 +100,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of StorageNetworkCreate from a dict""" if obj is None: return None @@ -114,7 +112,7 @@ def from_dict(cls, obj: Dict) -> Self: "name": obj.get("name"), "description": obj.get("description"), "location": obj.get("location"), - "volumes": [StorageNetworkVolumeCreate.from_dict(_item) for _item in obj.get("volumes")] if obj.get("volumes") is not None else None, + "volumes": [StorageNetworkVolumeCreate.from_dict(_item) for _item in obj["volumes"]] if obj.get("volumes") is not None else None, "clientVlan": obj.get("clientVlan") }) # store additional fields in additional_properties diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_update.py b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_update.py index d83dfb7d..d799eee1 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_update.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_update.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class StorageNetworkUpdate(BaseModel): """ @@ -47,11 +43,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9(). -])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -64,7 +60,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of StorageNetworkUpdate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -79,11 +75,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -94,7 +92,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of StorageNetworkUpdate from a dict""" if obj is None: return None diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_volume_create.py b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_volume_create.py index b45e318a..907acc4a 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_volume_create.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/storage_network_volume_create.py @@ -18,16 +18,12 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_network_storage_api.models.tag_assignment_request import TagAssignmentRequest -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class StorageNetworkVolumeCreate(BaseModel): """ @@ -58,11 +54,11 @@ def path_suffix_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(\/[\w-]+)+$|^$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -75,7 +71,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of StorageNetworkVolumeCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -90,19 +86,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -112,7 +110,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of StorageNetworkVolumeCreate from a dict""" if obj is None: return None @@ -125,7 +123,7 @@ def from_dict(cls, obj: Dict) -> Self: "description": obj.get("description"), "pathSuffix": obj.get("pathSuffix"), "capacityInGb": obj.get("capacityInGb"), - "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None + "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment.py b/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment.py index 47926b50..0cadddb6 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagAssignment(BaseModel): """ @@ -45,15 +41,15 @@ def created_by_validate_enum(cls, value): if value is None: return value - if value not in ('USER', 'SYSTEM'): + if value not in set(['USER', 'SYSTEM']): raise ValueError("must be one of enum values ('USER', 'SYSTEM')") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +62,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagAssignment from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -81,11 +77,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -96,7 +94,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagAssignment from a dict""" if obj is None: return None diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment_request.py b/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment_request.py index ed88f779..55e2a307 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment_request.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/tag_assignment_request.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagAssignmentRequest(BaseModel): """ @@ -36,11 +32,11 @@ class TagAssignmentRequest(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["name", "value"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagAssignmentRequest from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagAssignmentRequest from a dict""" if obj is None: return None diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/volume.py b/pnap_network_storage_api/pnap_network_storage_api/models/volume.py index eeef650a..81b7fff1 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/volume.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/volume.py @@ -19,16 +19,13 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr -from pydantic import Field from pnap_network_storage_api.models.permissions import Permissions from pnap_network_storage_api.models.status import Status from pnap_network_storage_api.models.tag_assignment import TagAssignment -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Volume(BaseModel): """ @@ -50,11 +47,11 @@ class Volume(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "name", "description", "path", "pathSuffix", "capacityInGb", "usedCapacityInGb", "protocol", "status", "createdOn", "deleteRequestedOn", "permissions", "tags"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -67,7 +64,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Volume from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -82,11 +79,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of permissions @@ -95,9 +94,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -107,7 +106,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Volume from a dict""" if obj is None: return None @@ -127,8 +126,8 @@ def from_dict(cls, obj: Dict) -> Self: "status": obj.get("status"), "createdOn": obj.get("createdOn"), "deleteRequestedOn": obj.get("deleteRequestedOn"), - "permissions": Permissions.from_dict(obj.get("permissions")) if obj.get("permissions") is not None else None, - "tags": [TagAssignment.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None + "permissions": Permissions.from_dict(obj["permissions"]) if obj.get("permissions") is not None else None, + "tags": [TagAssignment.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/volume_create.py b/pnap_network_storage_api/pnap_network_storage_api/models/volume_create.py index b82839bc..5da95370 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/volume_create.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/volume_create.py @@ -18,17 +18,13 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_network_storage_api.models.permissions_create import PermissionsCreate from pnap_network_storage_api.models.tag_assignment_request import TagAssignmentRequest -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class VolumeCreate(BaseModel): """ @@ -60,11 +56,11 @@ def path_suffix_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(\/[\w-]+)+$|^$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -77,7 +73,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of VolumeCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -92,11 +88,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of permissions @@ -105,9 +103,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in tags (list) _items = [] if self.tags: - for _item in self.tags: - if _item: - _items.append(_item.to_dict()) + for _item_tags in self.tags: + if _item_tags: + _items.append(_item_tags.to_dict()) _dict['tags'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -117,7 +115,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of VolumeCreate from a dict""" if obj is None: return None @@ -130,8 +128,8 @@ def from_dict(cls, obj: Dict) -> Self: "description": obj.get("description"), "pathSuffix": obj.get("pathSuffix"), "capacityInGb": obj.get("capacityInGb"), - "permissions": PermissionsCreate.from_dict(obj.get("permissions")) if obj.get("permissions") is not None else None, - "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj.get("tags")] if obj.get("tags") is not None else None + "permissions": PermissionsCreate.from_dict(obj["permissions"]) if obj.get("permissions") is not None else None, + "tags": [TagAssignmentRequest.from_dict(_item) for _item in obj["tags"]] if obj.get("tags") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/models/volume_update.py b/pnap_network_storage_api/pnap_network_storage_api/models/volume_update.py index 079cbcf3..8fbfbce3 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/models/volume_update.py +++ b/pnap_network_storage_api/pnap_network_storage_api/models/volume_update.py @@ -18,16 +18,12 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_network_storage_api.models.permissions_update import PermissionsUpdate -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class VolumeUpdate(BaseModel): """ @@ -61,11 +57,11 @@ def path_suffix_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(\/[\w-]+)+$|^$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -78,7 +74,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of VolumeUpdate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -93,11 +89,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of permissions @@ -111,7 +109,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of VolumeUpdate from a dict""" if obj is None: return None @@ -124,7 +122,7 @@ def from_dict(cls, obj: Dict) -> Self: "description": obj.get("description"), "capacityInGb": obj.get("capacityInGb"), "pathSuffix": obj.get("pathSuffix"), - "permissions": PermissionsUpdate.from_dict(obj.get("permissions")) if obj.get("permissions") is not None else None + "permissions": PermissionsUpdate.from_dict(obj["permissions"]) if obj.get("permissions") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_network_storage_api/pnap_network_storage_api/rest.py b/pnap_network_storage_api/pnap_network_storage_api/rest.py index 773c7fd8..abccf289 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/rest.py +++ b/pnap_network_storage_api/pnap_network_storage_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_network_storage_api/pnap_network_storage_api/version.py b/pnap_network_storage_api/pnap_network_storage_api/version.py index c756f9c5..09091e00 100644 --- a/pnap_network_storage_api/pnap_network_storage_api/version.py +++ b/pnap_network_storage_api/pnap_network_storage_api/version.py @@ -1 +1 @@ -VERSION = "2.0.4" \ No newline at end of file +VERSION = "2.0.5" \ No newline at end of file diff --git a/pnap_network_storage_api/pyproject.toml b/pnap_network_storage_api/pyproject.toml index 761a8991..db72edbb 100644 --- a/pnap_network_storage_api/pyproject.toml +++ b/pnap_network_storage_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_network_storage_api" -version = "2.0.4" +version = "2.0.5" description = "Network Storage API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Network Storage API"] -include = ["pnap_network_storage_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_network_storage_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_network_storage_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_network_storage_api/requirements.txt b/pnap_network_storage_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_network_storage_api/requirements.txt +++ b/pnap_network_storage_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_network_storage_api/setup.py b/pnap_network_storage_api/setup.py index 608b793b..63b76695 100644 --- a/pnap_network_storage_api/setup.py +++ b/pnap_network_storage_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Network Storage API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_network_storage_api" -VERSION = "2.0.4" -PYTHON_REQUIRES = ">=3.7" +VERSION = "2.0.5" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ Create, list, edit, and delete storage networks with the Network Storage API. Use storage networks to expand storage capacity on a private network. <br> <span class='pnap-api-knowledge-base-link'> Knowledge base articles to help you can be found <a href='https://phoenixnap.com/kb/bare-metal-cloud-storage' target='_blank'>here</a> </span> <br> <b>All URLs are relative to (https://api.phoenixnap.com/network-storage/v1/)</b> """, # noqa: E501 package_data={"pnap_network_storage_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_payments_api/README.md b/pnap_payments_api/README.md index 2d635c50..2264f26d 100644 --- a/pnap_payments_api/README.md +++ b/pnap_payments_api/README.md @@ -4,13 +4,13 @@ Payments API are currently designed to fetch Transactions only. This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 0.1 -- Package version: 1.0.4 +- Package version: 1.0.5 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -40,9 +40,16 @@ Then import the package: import pnap_payments_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_payments_api from pnap_payments_api.rest import ApiException from pprint import pprint @@ -93,6 +100,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -134,4 +142,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_payments_api/docs/CardPaymentMethodDetails.md b/pnap_payments_api/docs/CardPaymentMethodDetails.md index 7ce2a1ea..bf8bc988 100644 --- a/pnap_payments_api/docs/CardPaymentMethodDetails.md +++ b/pnap_payments_api/docs/CardPaymentMethodDetails.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of CardPaymentMethodDetails from a JSON string card_payment_method_details_instance = CardPaymentMethodDetails.from_json(json) # print the JSON string representation of the object -print CardPaymentMethodDetails.to_json() +print(CardPaymentMethodDetails.to_json()) # convert the object into a dict card_payment_method_details_dict = card_payment_method_details_instance.to_dict() # create an instance of CardPaymentMethodDetails from a dict -card_payment_method_details_form_dict = card_payment_method_details.from_dict(card_payment_method_details_dict) +card_payment_method_details_from_dict = CardPaymentMethodDetails.from_dict(card_payment_method_details_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_payments_api/docs/Error.md b/pnap_payments_api/docs/Error.md index 6208737c..efaebdb4 100644 --- a/pnap_payments_api/docs/Error.md +++ b/pnap_payments_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_payments_api/docs/PaginatedResponse.md b/pnap_payments_api/docs/PaginatedResponse.md index 144cb83b..65fca390 100644 --- a/pnap_payments_api/docs/PaginatedResponse.md +++ b/pnap_payments_api/docs/PaginatedResponse.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of PaginatedResponse from a JSON string paginated_response_instance = PaginatedResponse.from_json(json) # print the JSON string representation of the object -print PaginatedResponse.to_json() +print(PaginatedResponse.to_json()) # convert the object into a dict paginated_response_dict = paginated_response_instance.to_dict() # create an instance of PaginatedResponse from a dict -paginated_response_form_dict = paginated_response.from_dict(paginated_response_dict) +paginated_response_from_dict = PaginatedResponse.from_dict(paginated_response_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_payments_api/docs/PaginatedTransactions.md b/pnap_payments_api/docs/PaginatedTransactions.md index 38bbd9a6..27573746 100644 --- a/pnap_payments_api/docs/PaginatedTransactions.md +++ b/pnap_payments_api/docs/PaginatedTransactions.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of PaginatedTransactions from a JSON string paginated_transactions_instance = PaginatedTransactions.from_json(json) # print the JSON string representation of the object -print PaginatedTransactions.to_json() +print(PaginatedTransactions.to_json()) # convert the object into a dict paginated_transactions_dict = paginated_transactions_instance.to_dict() # create an instance of PaginatedTransactions from a dict -paginated_transactions_form_dict = paginated_transactions.from_dict(paginated_transactions_dict) +paginated_transactions_from_dict = PaginatedTransactions.from_dict(paginated_transactions_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_payments_api/docs/Transaction.md b/pnap_payments_api/docs/Transaction.md index e00386a4..a9ed5343 100644 --- a/pnap_payments_api/docs/Transaction.md +++ b/pnap_payments_api/docs/Transaction.md @@ -25,12 +25,12 @@ json = "{}" # create an instance of Transaction from a JSON string transaction_instance = Transaction.from_json(json) # print the JSON string representation of the object -print Transaction.to_json() +print(Transaction.to_json()) # convert the object into a dict transaction_dict = transaction_instance.to_dict() # create an instance of Transaction from a dict -transaction_form_dict = transaction.from_dict(transaction_dict) +transaction_from_dict = Transaction.from_dict(transaction_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_payments_api/docs/TransactionMetadata.md b/pnap_payments_api/docs/TransactionMetadata.md index c4a2fc6c..4d8352be 100644 --- a/pnap_payments_api/docs/TransactionMetadata.md +++ b/pnap_payments_api/docs/TransactionMetadata.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of TransactionMetadata from a JSON string transaction_metadata_instance = TransactionMetadata.from_json(json) # print the JSON string representation of the object -print TransactionMetadata.to_json() +print(TransactionMetadata.to_json()) # convert the object into a dict transaction_metadata_dict = transaction_metadata_instance.to_dict() # create an instance of TransactionMetadata from a dict -transaction_metadata_form_dict = transaction_metadata.from_dict(transaction_metadata_dict) +transaction_metadata_from_dict = TransactionMetadata.from_dict(transaction_metadata_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_payments_api/docs/TransactionsApi.md b/pnap_payments_api/docs/TransactionsApi.md index 319ea33c..d45af97c 100644 --- a/pnap_payments_api/docs/TransactionsApi.md +++ b/pnap_payments_api/docs/TransactionsApi.md @@ -20,8 +20,6 @@ Get transaction details. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_payments_api from pnap_payments_api.models.transaction import Transaction from pnap_payments_api.rest import ApiException @@ -100,8 +98,6 @@ A paginated list of client's transactions. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_payments_api from pnap_payments_api.models.paginated_transactions import PaginatedTransactions from pnap_payments_api.rest import ApiException @@ -126,8 +122,8 @@ with pnap_payments_api.ApiClient(configuration) as api_client: api_instance = pnap_payments_api.TransactionsApi(api_client) limit = 100 # int | The limit of the number of results returned. The number of records returned may be smaller than the limit. (optional) (default to 100) offset = 0 # int | The number of items to skip in the results. (optional) (default to 0) - sort_direction = 'DESC' # str | Sort Given Field depending on the desired direction. Default sorting is descending. (optional) (default to 'DESC') - sort_field = 'date' # str | If a sortField is requested, pagination will be done after sorting. Default sorting is by date. (optional) (default to 'date') + sort_direction = DESC # str | Sort Given Field depending on the desired direction. Default sorting is descending. (optional) (default to DESC) + sort_field = date # str | If a sortField is requested, pagination will be done after sorting. Default sorting is by date. (optional) (default to date) var_from = '2021-04-27T16:24:57.123Z' # datetime | From the date and time (inclusive) to filter transactions by. (optional) to = '2021-04-29T16:24:57.123Z' # datetime | To the date and time (inclusive) to filter transactions by. (optional) @@ -149,8 +145,8 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **limit** | **int**| The limit of the number of results returned. The number of records returned may be smaller than the limit. | [optional] [default to 100] **offset** | **int**| The number of items to skip in the results. | [optional] [default to 0] - **sort_direction** | **str**| Sort Given Field depending on the desired direction. Default sorting is descending. | [optional] [default to 'DESC'] - **sort_field** | **str**| If a sortField is requested, pagination will be done after sorting. Default sorting is by date. | [optional] [default to 'date'] + **sort_direction** | **str**| Sort Given Field depending on the desired direction. Default sorting is descending. | [optional] [default to DESC] + **sort_field** | **str**| If a sortField is requested, pagination will be done after sorting. Default sorting is by date. | [optional] [default to date] **var_from** | **datetime**| From the date and time (inclusive) to filter transactions by. | [optional] **to** | **datetime**| To the date and time (inclusive) to filter transactions by. | [optional] diff --git a/pnap_payments_api/pnap_payments_api/__init__.py b/pnap_payments_api/pnap_payments_api/__init__.py index 381d4e3a..5b2594cb 100644 --- a/pnap_payments_api/pnap_payments_api/__init__.py +++ b/pnap_payments_api/pnap_payments_api/__init__.py @@ -15,26 +15,47 @@ """ # noqa: E501 -__version__ = "1.0.4" +__version__ = "1.0.5" + +# Define package exports +__all__ = [ + "TransactionsApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "CardPaymentMethodDetails", + "Error", + "PaginatedResponse", + "PaginatedTransactions", + "Transaction", + "TransactionMetadata", +] # import apis into sdk package -from pnap_payments_api.api.transactions_api import TransactionsApi +from pnap_payments_api.api.transactions_api import TransactionsApi as TransactionsApi # import ApiClient -from pnap_payments_api.api_response import ApiResponse -from pnap_payments_api.api_client import ApiClient -from pnap_payments_api.configuration import Configuration -from pnap_payments_api.exceptions import OpenApiException -from pnap_payments_api.exceptions import ApiTypeError -from pnap_payments_api.exceptions import ApiValueError -from pnap_payments_api.exceptions import ApiKeyError -from pnap_payments_api.exceptions import ApiAttributeError -from pnap_payments_api.exceptions import ApiException +from pnap_payments_api.api_response import ApiResponse as ApiResponse +from pnap_payments_api.api_client import ApiClient as ApiClient +from pnap_payments_api.configuration import Configuration as Configuration +from pnap_payments_api.exceptions import OpenApiException as OpenApiException +from pnap_payments_api.exceptions import ApiTypeError as ApiTypeError +from pnap_payments_api.exceptions import ApiValueError as ApiValueError +from pnap_payments_api.exceptions import ApiKeyError as ApiKeyError +from pnap_payments_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_payments_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_payments_api.models.card_payment_method_details import CardPaymentMethodDetails -from pnap_payments_api.models.error import Error -from pnap_payments_api.models.paginated_response import PaginatedResponse -from pnap_payments_api.models.paginated_transactions import PaginatedTransactions -from pnap_payments_api.models.transaction import Transaction -from pnap_payments_api.models.transaction_metadata import TransactionMetadata +from pnap_payments_api.models.card_payment_method_details import CardPaymentMethodDetails as CardPaymentMethodDetails +from pnap_payments_api.models.error import Error as Error +from pnap_payments_api.models.paginated_response import PaginatedResponse as PaginatedResponse +from pnap_payments_api.models.paginated_transactions import PaginatedTransactions as PaginatedTransactions +from pnap_payments_api.models.transaction import Transaction as Transaction +from pnap_payments_api.models.transaction_metadata import TransactionMetadata as TransactionMetadata + diff --git a/pnap_payments_api/pnap_payments_api/api/transactions_api.py b/pnap_payments_api/pnap_payments_api/api/transactions_api.py index 52c31e24..3fd44d8f 100644 --- a/pnap_payments_api/pnap_payments_api/api/transactions_api.py +++ b/pnap_payments_api/pnap_payments_api/api/transactions_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Payments API @@ -13,29 +11,19 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from datetime import datetime - -from pydantic import StrictStr, field_validator +from datetime import datetime +from pydantic import Field, StrictStr, field_validator from typing import Optional - +from typing_extensions import Annotated from pnap_payments_api.models.paginated_transactions import PaginatedTransactions from pnap_payments_api.models.transaction import Transaction -from pnap_payments_api.api_client import ApiClient +from pnap_payments_api.api_client import ApiClient, RequestSerialized from pnap_payments_api.api_response import ApiResponse from pnap_payments_api.rest import RESTResponseType @@ -266,7 +254,7 @@ def _transaction_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -277,7 +265,9 @@ def _transaction_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -290,11 +280,12 @@ def _transaction_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -601,7 +592,7 @@ def _transactions_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -612,7 +603,9 @@ def _transactions_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -665,11 +658,12 @@ def _transactions_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting diff --git a/pnap_payments_api/pnap_payments_api/api_client.py b/pnap_payments_api/pnap_payments_api/api_client.py index b2cf90eb..628ddccb 100644 --- a/pnap_payments_api/pnap_payments_api/api_client.py +++ b/pnap_payments_api/pnap_payments_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Payments API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_payments_api.configuration import Configuration -from pnap_payments_api.api_response import ApiResponse +from pnap_payments_api.api_response import ApiResponse, T as ApiResponseT import pnap_payments_api.models from pnap_payments_api import rest from pnap_payments_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_payments_api/1.0.4" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_payments_api/1.0.5" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_payments_api/1.0.4" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_payments_api/1.0.5" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_payments_api/pnap_payments_api/api_response.py b/pnap_payments_api/pnap_payments_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_payments_api/pnap_payments_api/api_response.py +++ b/pnap_payments_api/pnap_payments_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_payments_api/pnap_payments_api/configuration.py b/pnap_payments_api/pnap_payments_api/configuration.py index 9dcac2f1..df9e456d 100644 --- a/pnap_payments_api/pnap_payments_api/configuration.py +++ b/pnap_payments_api/pnap_payments_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Payments API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/payments/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 0.1\n"\ - "SDK Package Version: 1.0.4".\ + "SDK Package Version: 1.0.5".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_payments_api/pnap_payments_api/exceptions.py b/pnap_payments_api/pnap_payments_api/exceptions.py index cd8cbfb5..2deaa789 100644 --- a/pnap_payments_api/pnap_payments_api/exceptions.py +++ b/pnap_payments_api/pnap_payments_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Payments API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_payments_api/pnap_payments_api/models/__init__.py b/pnap_payments_api/pnap_payments_api/models/__init__.py index 20d9cba3..0127ccee 100644 --- a/pnap_payments_api/pnap_payments_api/models/__init__.py +++ b/pnap_payments_api/pnap_payments_api/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_payments_api.models.card_payment_method_details import CardPaymentMethodDetails from pnap_payments_api.models.error import Error @@ -21,3 +20,4 @@ from pnap_payments_api.models.paginated_transactions import PaginatedTransactions from pnap_payments_api.models.transaction import Transaction from pnap_payments_api.models.transaction_metadata import TransactionMetadata + diff --git a/pnap_payments_api/pnap_payments_api/models/card_payment_method_details.py b/pnap_payments_api/pnap_payments_api/models/card_payment_method_details.py index a475f866..56fabbdc 100644 --- a/pnap_payments_api/pnap_payments_api/models/card_payment_method_details.py +++ b/pnap_payments_api/pnap_payments_api/models/card_payment_method_details.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class CardPaymentMethodDetails(BaseModel): """ @@ -44,11 +40,11 @@ def last_four_digits_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /\d{4}$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -61,7 +57,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of CardPaymentMethodDetails from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -76,11 +72,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -91,7 +89,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of CardPaymentMethodDetails from a dict""" if obj is None: return None diff --git a/pnap_payments_api/pnap_payments_api/models/error.py b/pnap_payments_api/pnap_payments_api/models/error.py index b606a0cd..8e18b1d5 100644 --- a/pnap_payments_api/pnap_payments_api/models/error.py +++ b/pnap_payments_api/pnap_payments_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_payments_api/pnap_payments_api/models/paginated_response.py b/pnap_payments_api/pnap_payments_api/models/paginated_response.py index 4ac3d53b..1424a69a 100644 --- a/pnap_payments_api/pnap_payments_api/models/paginated_response.py +++ b/pnap_payments_api/pnap_payments_api/models/paginated_response.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictInt -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PaginatedResponse(BaseModel): """ @@ -37,11 +33,11 @@ class PaginatedResponse(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["limit", "offset", "total"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PaginatedResponse from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PaginatedResponse from a dict""" if obj is None: return None diff --git a/pnap_payments_api/pnap_payments_api/models/paginated_transactions.py b/pnap_payments_api/pnap_payments_api/models/paginated_transactions.py index 97882749..6af48090 100644 --- a/pnap_payments_api/pnap_payments_api/models/paginated_transactions.py +++ b/pnap_payments_api/pnap_payments_api/models/paginated_transactions.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictInt -from pydantic import Field from pnap_payments_api.models.transaction import Transaction -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class PaginatedTransactions(BaseModel): """ @@ -39,11 +35,11 @@ class PaginatedTransactions(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["limit", "offset", "total", "results"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -56,7 +52,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of PaginatedTransactions from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -71,19 +67,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in results (list) _items = [] if self.results: - for _item in self.results: - if _item: - _items.append(_item.to_dict()) + for _item_results in self.results: + if _item_results: + _items.append(_item_results.to_dict()) _dict['results'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -93,7 +91,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of PaginatedTransactions from a dict""" if obj is None: return None @@ -105,7 +103,7 @@ def from_dict(cls, obj: Dict) -> Self: "limit": obj.get("limit"), "offset": obj.get("offset"), "total": obj.get("total"), - "results": [Transaction.from_dict(_item) for _item in obj.get("results")] if obj.get("results") is not None else None + "results": [Transaction.from_dict(_item) for _item in obj["results"]] if obj.get("results") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_payments_api/pnap_payments_api/models/transaction.py b/pnap_payments_api/pnap_payments_api/models/transaction.py index e9ffc6a1..123dc46a 100644 --- a/pnap_payments_api/pnap_payments_api/models/transaction.py +++ b/pnap_payments_api/pnap_payments_api/models/transaction.py @@ -19,15 +19,12 @@ import json from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional, Union -from pydantic import BaseModel, StrictFloat, StrictInt, StrictStr -from pydantic import Field from pnap_payments_api.models.card_payment_method_details import CardPaymentMethodDetails from pnap_payments_api.models.transaction_metadata import TransactionMetadata -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Transaction(BaseModel): """ @@ -44,11 +41,11 @@ class Transaction(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "status", "details", "amount", "currency", "date", "metadata", "cardPaymentMethodDetails"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -61,7 +58,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Transaction from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -76,11 +73,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of metadata @@ -97,7 +96,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Transaction from a dict""" if obj is None: return None @@ -112,8 +111,8 @@ def from_dict(cls, obj: Dict) -> Self: "amount": obj.get("amount"), "currency": obj.get("currency"), "date": obj.get("date"), - "metadata": TransactionMetadata.from_dict(obj.get("metadata")) if obj.get("metadata") is not None else None, - "cardPaymentMethodDetails": CardPaymentMethodDetails.from_dict(obj.get("cardPaymentMethodDetails")) if obj.get("cardPaymentMethodDetails") is not None else None + "metadata": TransactionMetadata.from_dict(obj["metadata"]) if obj.get("metadata") is not None else None, + "cardPaymentMethodDetails": CardPaymentMethodDetails.from_dict(obj["cardPaymentMethodDetails"]) if obj.get("cardPaymentMethodDetails") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_payments_api/pnap_payments_api/models/transaction_metadata.py b/pnap_payments_api/pnap_payments_api/models/transaction_metadata.py index 039183fb..ffc8d405 100644 --- a/pnap_payments_api/pnap_payments_api/models/transaction_metadata.py +++ b/pnap_payments_api/pnap_payments_api/models/transaction_metadata.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TransactionMetadata(BaseModel): """ @@ -37,11 +33,11 @@ class TransactionMetadata(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["invoiceId", "invoiceNumber", "isAutoCharge"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TransactionMetadata from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TransactionMetadata from a dict""" if obj is None: return None diff --git a/pnap_payments_api/pnap_payments_api/rest.py b/pnap_payments_api/pnap_payments_api/rest.py index a48a34ef..0bd3fb5f 100644 --- a/pnap_payments_api/pnap_payments_api/rest.py +++ b/pnap_payments_api/pnap_payments_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_payments_api/pnap_payments_api/version.py b/pnap_payments_api/pnap_payments_api/version.py index dc4e9f63..92f6d2de 100644 --- a/pnap_payments_api/pnap_payments_api/version.py +++ b/pnap_payments_api/pnap_payments_api/version.py @@ -1 +1 @@ -VERSION = "1.0.4" \ No newline at end of file +VERSION = "1.0.5" \ No newline at end of file diff --git a/pnap_payments_api/pyproject.toml b/pnap_payments_api/pyproject.toml index d2ab5e87..bd3021a7 100644 --- a/pnap_payments_api/pyproject.toml +++ b/pnap_payments_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_payments_api" -version = "1.0.4" +version = "1.0.5" description = "Payments API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Payments API"] -include = ["pnap_payments_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_payments_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_payments_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_payments_api/requirements.txt b/pnap_payments_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_payments_api/requirements.txt +++ b/pnap_payments_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_payments_api/setup.py b/pnap_payments_api/setup.py index f9f8906f..6d1657c0 100644 --- a/pnap_payments_api/setup.py +++ b/pnap_payments_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Payments API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_payments_api" -VERSION = "1.0.4" -PYTHON_REQUIRES = ">=3.7" +VERSION = "1.0.5" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ Payments API are currently designed to fetch Transactions only. """, # noqa: E501 package_data={"pnap_payments_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_rancher_solution_api/README.md b/pnap_rancher_solution_api/README.md index 3881e7b5..c15c382b 100644 --- a/pnap_rancher_solution_api/README.md +++ b/pnap_rancher_solution_api/README.md @@ -13,13 +13,13 @@ Knowledge base articles to help you can be found This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 0.1 -- Package version: 2.0.4 +- Package version: 2.0.5 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -49,9 +49,16 @@ Then import the package: import pnap_rancher_solution_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_rancher_solution_api from pnap_rancher_solution_api.rest import ApiException from pprint import pprint @@ -101,6 +108,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -148,4 +156,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_rancher_solution_api/docs/Cluster.md b/pnap_rancher_solution_api/docs/Cluster.md index d6315e89..5c4e6beb 100644 --- a/pnap_rancher_solution_api/docs/Cluster.md +++ b/pnap_rancher_solution_api/docs/Cluster.md @@ -9,7 +9,7 @@ Name | Type | Description | Notes **id** | **str** | (Read-only) The Cluster identifier. | [optional] [readonly] **name** | **str** | Cluster name. This field is autogenerated if not provided. | [optional] **description** | **str** | Cluster description. | [optional] -**location** | **str** | Deployment location. Cannot be changed once a cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. | +**location** | **str** | Deployment location. Cannot be changed once a cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. | **initial_cluster_version** | **str** | (Read-only) The Rancher version that was installed on the cluster during the first creation process. | [optional] [readonly] **node_pools** | [**List[NodePool]**](NodePool.md) | The node pools associated with the cluster. | [optional] **configuration** | [**RancherClusterConfig**](RancherClusterConfig.md) | | [optional] @@ -27,12 +27,12 @@ json = "{}" # create an instance of Cluster from a JSON string cluster_instance = Cluster.from_json(json) # print the JSON string representation of the object -print Cluster.to_json() +print(Cluster.to_json()) # convert the object into a dict cluster_dict = cluster_instance.to_dict() # create an instance of Cluster from a dict -cluster_form_dict = cluster.from_dict(cluster_dict) +cluster_from_dict = Cluster.from_dict(cluster_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/ClustersApi.md b/pnap_rancher_solution_api/docs/ClustersApi.md index 6f36a5ac..cad3c15d 100644 --- a/pnap_rancher_solution_api/docs/ClustersApi.md +++ b/pnap_rancher_solution_api/docs/ClustersApi.md @@ -22,8 +22,6 @@ Cluster list. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_rancher_solution_api from pnap_rancher_solution_api.models.cluster import Cluster from pnap_rancher_solution_api.rest import ApiException @@ -98,8 +96,6 @@ Delete a cluster. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_rancher_solution_api from pnap_rancher_solution_api.models.delete_result import DeleteResult from pnap_rancher_solution_api.rest import ApiException @@ -178,8 +174,6 @@ Retrieve a Cluster * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_rancher_solution_api from pnap_rancher_solution_api.models.cluster import Cluster from pnap_rancher_solution_api.rest import ApiException @@ -251,15 +245,15 @@ Name | Type | Description | Notes Create a Rancher Server Deployment. -Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. +Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. +This is not a Downstream User Cluster. Knowledge base article to help you can be found here. + ### Example * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_rancher_solution_api from pnap_rancher_solution_api.models.cluster import Cluster from pnap_rancher_solution_api.rest import ApiException diff --git a/pnap_rancher_solution_api/docs/DeleteResult.md b/pnap_rancher_solution_api/docs/DeleteResult.md index ec4a2b8a..01e63e72 100644 --- a/pnap_rancher_solution_api/docs/DeleteResult.md +++ b/pnap_rancher_solution_api/docs/DeleteResult.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of DeleteResult from a JSON string delete_result_instance = DeleteResult.from_json(json) # print the JSON string representation of the object -print DeleteResult.to_json() +print(DeleteResult.to_json()) # convert the object into a dict delete_result_dict = delete_result_instance.to_dict() # create an instance of DeleteResult from a dict -delete_result_form_dict = delete_result.from_dict(delete_result_dict) +delete_result_from_dict = DeleteResult.from_dict(delete_result_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/Error.md b/pnap_rancher_solution_api/docs/Error.md index 9c1f5889..28139b10 100644 --- a/pnap_rancher_solution_api/docs/Error.md +++ b/pnap_rancher_solution_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/Node.md b/pnap_rancher_solution_api/docs/Node.md index f85ef3a1..77228400 100644 --- a/pnap_rancher_solution_api/docs/Node.md +++ b/pnap_rancher_solution_api/docs/Node.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Node from a JSON string node_instance = Node.from_json(json) # print the JSON string representation of the object -print Node.to_json() +print(Node.to_json()) # convert the object into a dict node_dict = node_instance.to_dict() # create an instance of Node from a dict -node_form_dict = node.from_dict(node_dict) +node_from_dict = Node.from_dict(node_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/NodePool.md b/pnap_rancher_solution_api/docs/NodePool.md index dc2814a0..b86668ae 100644 --- a/pnap_rancher_solution_api/docs/NodePool.md +++ b/pnap_rancher_solution_api/docs/NodePool.md @@ -22,12 +22,12 @@ json = "{}" # create an instance of NodePool from a JSON string node_pool_instance = NodePool.from_json(json) # print the JSON string representation of the object -print NodePool.to_json() +print(NodePool.to_json()) # convert the object into a dict node_pool_dict = node_pool_instance.to_dict() # create an instance of NodePool from a dict -node_pool_form_dict = node_pool.from_dict(node_pool_dict) +node_pool_from_dict = NodePool.from_dict(node_pool_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/RancherClusterCertificates.md b/pnap_rancher_solution_api/docs/RancherClusterCertificates.md index 2530cce5..1e1f0d88 100644 --- a/pnap_rancher_solution_api/docs/RancherClusterCertificates.md +++ b/pnap_rancher_solution_api/docs/RancherClusterCertificates.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of RancherClusterCertificates from a JSON string rancher_cluster_certificates_instance = RancherClusterCertificates.from_json(json) # print the JSON string representation of the object -print RancherClusterCertificates.to_json() +print(RancherClusterCertificates.to_json()) # convert the object into a dict rancher_cluster_certificates_dict = rancher_cluster_certificates_instance.to_dict() # create an instance of RancherClusterCertificates from a dict -rancher_cluster_certificates_form_dict = rancher_cluster_certificates.from_dict(rancher_cluster_certificates_dict) +rancher_cluster_certificates_from_dict = RancherClusterCertificates.from_dict(rancher_cluster_certificates_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/RancherClusterConfig.md b/pnap_rancher_solution_api/docs/RancherClusterConfig.md index 06a834bc..7c866b06 100644 --- a/pnap_rancher_solution_api/docs/RancherClusterConfig.md +++ b/pnap_rancher_solution_api/docs/RancherClusterConfig.md @@ -24,12 +24,12 @@ json = "{}" # create an instance of RancherClusterConfig from a JSON string rancher_cluster_config_instance = RancherClusterConfig.from_json(json) # print the JSON string representation of the object -print RancherClusterConfig.to_json() +print(RancherClusterConfig.to_json()) # convert the object into a dict rancher_cluster_config_dict = rancher_cluster_config_instance.to_dict() # create an instance of RancherClusterConfig from a dict -rancher_cluster_config_form_dict = rancher_cluster_config.from_dict(rancher_cluster_config_dict) +rancher_cluster_config_from_dict = RancherClusterConfig.from_dict(rancher_cluster_config_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/RancherServerMetadata.md b/pnap_rancher_solution_api/docs/RancherServerMetadata.md index 97684662..40f4d875 100644 --- a/pnap_rancher_solution_api/docs/RancherServerMetadata.md +++ b/pnap_rancher_solution_api/docs/RancherServerMetadata.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of RancherServerMetadata from a JSON string rancher_server_metadata_instance = RancherServerMetadata.from_json(json) # print the JSON string representation of the object -print RancherServerMetadata.to_json() +print(RancherServerMetadata.to_json()) # convert the object into a dict rancher_server_metadata_dict = rancher_server_metadata_instance.to_dict() # create an instance of RancherServerMetadata from a dict -rancher_server_metadata_form_dict = rancher_server_metadata.from_dict(rancher_server_metadata_dict) +rancher_server_metadata_from_dict = RancherServerMetadata.from_dict(rancher_server_metadata_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/SshConfig.md b/pnap_rancher_solution_api/docs/SshConfig.md index a7af1dc9..f84eb204 100644 --- a/pnap_rancher_solution_api/docs/SshConfig.md +++ b/pnap_rancher_solution_api/docs/SshConfig.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of SshConfig from a JSON string ssh_config_instance = SshConfig.from_json(json) # print the JSON string representation of the object -print SshConfig.to_json() +print(SshConfig.to_json()) # convert the object into a dict ssh_config_dict = ssh_config_instance.to_dict() # create an instance of SshConfig from a dict -ssh_config_form_dict = ssh_config.from_dict(ssh_config_dict) +ssh_config_from_dict = SshConfig.from_dict(ssh_config_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/docs/WorkloadClusterConfig.md b/pnap_rancher_solution_api/docs/WorkloadClusterConfig.md index 1c8b819f..76893b65 100644 --- a/pnap_rancher_solution_api/docs/WorkloadClusterConfig.md +++ b/pnap_rancher_solution_api/docs/WorkloadClusterConfig.md @@ -8,8 +8,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **name** | **str** | The name of the workload cluster. This field is autogenerated if not provided. | [optional] **server_count** | **int** | Number of configured servers. Currently only server counts of 1 and 3 are possible. | [optional] [default to 1] -**server_type** | **str** | Node server type. Cannot be changed once the cluster is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge` or `d3.g2.c3.xlarge`. | [default to 's0.d1.small'] -**location** | **str** | Workload cluster location. Cannot be changed once cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. | +**server_type** | **str** | Node server type. Cannot be changed once the cluster is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge` or `d3.g2.c3.xlarge`. | [default to 's0.d1.small'] +**location** | **str** | Workload cluster location. Cannot be changed once cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. | ## Example @@ -21,12 +21,12 @@ json = "{}" # create an instance of WorkloadClusterConfig from a JSON string workload_cluster_config_instance = WorkloadClusterConfig.from_json(json) # print the JSON string representation of the object -print WorkloadClusterConfig.to_json() +print(WorkloadClusterConfig.to_json()) # convert the object into a dict workload_cluster_config_dict = workload_cluster_config_instance.to_dict() # create an instance of WorkloadClusterConfig from a dict -workload_cluster_config_form_dict = workload_cluster_config.from_dict(workload_cluster_config_dict) +workload_cluster_config_from_dict = WorkloadClusterConfig.from_dict(workload_cluster_config_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/__init__.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/__init__.py index 88c473fc..7294adcb 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/__init__.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/__init__.py @@ -15,30 +15,55 @@ """ # noqa: E501 -__version__ = "2.0.4" +__version__ = "2.0.5" + +# Define package exports +__all__ = [ + "ClustersApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "Cluster", + "DeleteResult", + "Error", + "Node", + "NodePool", + "RancherClusterCertificates", + "RancherClusterConfig", + "RancherServerMetadata", + "SshConfig", + "WorkloadClusterConfig", +] # import apis into sdk package -from pnap_rancher_solution_api.api.clusters_api import ClustersApi +from pnap_rancher_solution_api.api.clusters_api import ClustersApi as ClustersApi # import ApiClient -from pnap_rancher_solution_api.api_response import ApiResponse -from pnap_rancher_solution_api.api_client import ApiClient -from pnap_rancher_solution_api.configuration import Configuration -from pnap_rancher_solution_api.exceptions import OpenApiException -from pnap_rancher_solution_api.exceptions import ApiTypeError -from pnap_rancher_solution_api.exceptions import ApiValueError -from pnap_rancher_solution_api.exceptions import ApiKeyError -from pnap_rancher_solution_api.exceptions import ApiAttributeError -from pnap_rancher_solution_api.exceptions import ApiException +from pnap_rancher_solution_api.api_response import ApiResponse as ApiResponse +from pnap_rancher_solution_api.api_client import ApiClient as ApiClient +from pnap_rancher_solution_api.configuration import Configuration as Configuration +from pnap_rancher_solution_api.exceptions import OpenApiException as OpenApiException +from pnap_rancher_solution_api.exceptions import ApiTypeError as ApiTypeError +from pnap_rancher_solution_api.exceptions import ApiValueError as ApiValueError +from pnap_rancher_solution_api.exceptions import ApiKeyError as ApiKeyError +from pnap_rancher_solution_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_rancher_solution_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_rancher_solution_api.models.cluster import Cluster -from pnap_rancher_solution_api.models.delete_result import DeleteResult -from pnap_rancher_solution_api.models.error import Error -from pnap_rancher_solution_api.models.node import Node -from pnap_rancher_solution_api.models.node_pool import NodePool -from pnap_rancher_solution_api.models.rancher_cluster_certificates import RancherClusterCertificates -from pnap_rancher_solution_api.models.rancher_cluster_config import RancherClusterConfig -from pnap_rancher_solution_api.models.rancher_server_metadata import RancherServerMetadata -from pnap_rancher_solution_api.models.ssh_config import SshConfig -from pnap_rancher_solution_api.models.workload_cluster_config import WorkloadClusterConfig +from pnap_rancher_solution_api.models.cluster import Cluster as Cluster +from pnap_rancher_solution_api.models.delete_result import DeleteResult as DeleteResult +from pnap_rancher_solution_api.models.error import Error as Error +from pnap_rancher_solution_api.models.node import Node as Node +from pnap_rancher_solution_api.models.node_pool import NodePool as NodePool +from pnap_rancher_solution_api.models.rancher_cluster_certificates import RancherClusterCertificates as RancherClusterCertificates +from pnap_rancher_solution_api.models.rancher_cluster_config import RancherClusterConfig as RancherClusterConfig +from pnap_rancher_solution_api.models.rancher_server_metadata import RancherServerMetadata as RancherServerMetadata +from pnap_rancher_solution_api.models.ssh_config import SshConfig as SshConfig +from pnap_rancher_solution_api.models.workload_cluster_config import WorkloadClusterConfig as WorkloadClusterConfig + diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/api/clusters_api.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/api/clusters_api.py index a05823c1..ffd7199f 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/api/clusters_api.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/api/clusters_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Rancher Solution API @@ -13,27 +11,18 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictStr +from pydantic import Field, StrictStr from typing import List - +from typing_extensions import Annotated from pnap_rancher_solution_api.models.cluster import Cluster from pnap_rancher_solution_api.models.delete_result import DeleteResult -from pnap_rancher_solution_api.api_client import ApiClient +from pnap_rancher_solution_api.api_client import ApiClient, RequestSerialized from pnap_rancher_solution_api.api_response import ApiResponse from pnap_rancher_solution_api.rest import RESTResponseType @@ -251,7 +240,7 @@ def _clusters_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -262,7 +251,9 @@ def _clusters_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -273,11 +264,12 @@ def _clusters_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -516,7 +508,7 @@ def _clusters_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -527,7 +519,9 @@ def _clusters_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -540,11 +534,12 @@ def _clusters_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -783,7 +778,7 @@ def _clusters_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -794,7 +789,9 @@ def _clusters_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -807,11 +804,12 @@ def _clusters_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -856,7 +854,7 @@ def clusters_post( ) -> Cluster: """Create a Rancher Server Deployment. - Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. + Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. :param cluster: (required) :type cluster: Cluster @@ -927,7 +925,7 @@ def clusters_post_with_http_info( ) -> ApiResponse[Cluster]: """Create a Rancher Server Deployment. - Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. + Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. :param cluster: (required) :type cluster: Cluster @@ -998,7 +996,7 @@ def clusters_post_without_preload_content( ) -> RESTResponseType: """Create a Rancher Server Deployment. - Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. + Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. :param cluster: (required) :type cluster: Cluster @@ -1053,7 +1051,7 @@ def _clusters_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1064,7 +1062,9 @@ def _clusters_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1077,11 +1077,12 @@ def _clusters_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/api_client.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/api_client.py index 66293ea5..c47f0f04 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/api_client.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Rancher Solution API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_rancher_solution_api.configuration import Configuration -from pnap_rancher_solution_api.api_response import ApiResponse +from pnap_rancher_solution_api.api_response import ApiResponse, T as ApiResponseT import pnap_rancher_solution_api.models from pnap_rancher_solution_api import rest from pnap_rancher_solution_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_rancher_solution_api/2.0.4" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_rancher_solution_api/2.0.5" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_rancher_solution_api/2.0.4" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_rancher_solution_api/2.0.5" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/api_response.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/api_response.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/configuration.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/configuration.py index 70c01dc0..834e22f3 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/configuration.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Rancher Solution API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/solutions/rancher/v1beta" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 0.1\n"\ - "SDK Package Version: 2.0.4".\ + "SDK Package Version: 2.0.5".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/exceptions.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/exceptions.py index 2d5c77a4..f407d6d2 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/exceptions.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Rancher Solution API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/__init__.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/__init__.py index ad115120..50360584 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/__init__.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_rancher_solution_api.models.cluster import Cluster from pnap_rancher_solution_api.models.delete_result import DeleteResult @@ -25,3 +24,4 @@ from pnap_rancher_solution_api.models.rancher_server_metadata import RancherServerMetadata from pnap_rancher_solution_api.models.ssh_config import SshConfig from pnap_rancher_solution_api.models.workload_cluster_config import WorkloadClusterConfig + diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/cluster.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/cluster.py index 0e60f982..e7e591e6 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/cluster.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/cluster.py @@ -18,19 +18,15 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field from typing_extensions import Annotated from pnap_rancher_solution_api.models.node_pool import NodePool from pnap_rancher_solution_api.models.rancher_cluster_config import RancherClusterConfig from pnap_rancher_solution_api.models.rancher_server_metadata import RancherServerMetadata from pnap_rancher_solution_api.models.workload_cluster_config import WorkloadClusterConfig -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Cluster(BaseModel): """ @@ -39,7 +35,7 @@ class Cluster(BaseModel): id: Optional[StrictStr] = Field(default=None, description="(Read-only) The Cluster identifier.") name: Optional[StrictStr] = Field(default=None, description="Cluster name. This field is autogenerated if not provided.") description: Optional[StrictStr] = Field(default=None, description="Cluster description.") - location: StrictStr = Field(description="Deployment location. Cannot be changed once a cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`.") + location: StrictStr = Field(description="Deployment location. Cannot be changed once a cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`.") initial_cluster_version: Optional[StrictStr] = Field(default=None, description="(Read-only) The Rancher version that was installed on the cluster during the first creation process.", alias="initialClusterVersion") node_pools: Optional[Annotated[List[NodePool], Field(min_length=1, max_length=1)]] = Field(default=None, description="The node pools associated with the cluster.", alias="nodePools") configuration: Optional[RancherClusterConfig] = None @@ -49,11 +45,11 @@ class Cluster(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["id", "name", "description", "location", "initialClusterVersion", "nodePools", "configuration", "metadata", "workloadConfiguration", "statusDescription"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -66,7 +62,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Cluster from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -85,23 +81,25 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "id", + "initial_cluster_version", + "metadata", + "status_description", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "id", - "initial_cluster_version", - "metadata", - "status_description", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in node_pools (list) _items = [] if self.node_pools: - for _item in self.node_pools: - if _item: - _items.append(_item.to_dict()) + for _item_node_pools in self.node_pools: + if _item_node_pools: + _items.append(_item_node_pools.to_dict()) _dict['nodePools'] = _items # override the default output from pydantic by calling `to_dict()` of configuration if self.configuration: @@ -120,7 +118,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Cluster from a dict""" if obj is None: return None @@ -134,10 +132,10 @@ def from_dict(cls, obj: Dict) -> Self: "description": obj.get("description"), "location": obj.get("location"), "initialClusterVersion": obj.get("initialClusterVersion"), - "nodePools": [NodePool.from_dict(_item) for _item in obj.get("nodePools")] if obj.get("nodePools") is not None else None, - "configuration": RancherClusterConfig.from_dict(obj.get("configuration")) if obj.get("configuration") is not None else None, - "metadata": RancherServerMetadata.from_dict(obj.get("metadata")) if obj.get("metadata") is not None else None, - "workloadConfiguration": WorkloadClusterConfig.from_dict(obj.get("workloadConfiguration")) if obj.get("workloadConfiguration") is not None else None, + "nodePools": [NodePool.from_dict(_item) for _item in obj["nodePools"]] if obj.get("nodePools") is not None else None, + "configuration": RancherClusterConfig.from_dict(obj["configuration"]) if obj.get("configuration") is not None else None, + "metadata": RancherServerMetadata.from_dict(obj["metadata"]) if obj.get("metadata") is not None else None, + "workloadConfiguration": WorkloadClusterConfig.from_dict(obj["workloadConfiguration"]) if obj.get("workloadConfiguration") is not None else None, "statusDescription": obj.get("statusDescription") }) # store additional fields in additional_properties diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/delete_result.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/delete_result.py index 6448bc16..9a61a779 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/delete_result.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/delete_result.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class DeleteResult(BaseModel): """ @@ -36,11 +32,11 @@ class DeleteResult(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["result", "clusterId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of DeleteResult from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of DeleteResult from a dict""" if obj is None: return None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/error.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/error.py index dea1cac7..a910d379 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/error.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,13 +66,15 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "message", + "validation_errors", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "message", - "validation_errors", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -87,7 +85,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node.py index 6e0c98bf..e89f4efe 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Node(BaseModel): """ @@ -35,11 +31,11 @@ class Node(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["serverId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -52,7 +48,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Node from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -67,11 +63,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -82,7 +80,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Node from a dict""" if obj is None: return None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node_pool.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node_pool.py index 7f3b2f1e..dddf8de0 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node_pool.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/node_pool.py @@ -18,17 +18,13 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr, field_validator -from pydantic import Field from typing_extensions import Annotated from pnap_rancher_solution_api.models.node import Node from pnap_rancher_solution_api.models.ssh_config import SshConfig -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class NodePool(BaseModel): """ @@ -52,11 +48,11 @@ def name_validate_regular_expression(cls, value): raise ValueError(r"must validate the regular expression /^(?=.*[a-zA-Z])([a-zA-Z0-9().-])+$/") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -69,7 +65,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of NodePool from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -85,12 +81,14 @@ def to_dict(self) -> Dict[str, Any]: * OpenAPI `readOnly` fields are excluded. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "nodes", + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "nodes", - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of ssh_config @@ -99,9 +97,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of each item in nodes (list) _items = [] if self.nodes: - for _item in self.nodes: - if _item: - _items.append(_item.to_dict()) + for _item_nodes in self.nodes: + if _item_nodes: + _items.append(_item_nodes.to_dict()) _dict['nodes'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -111,7 +109,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of NodePool from a dict""" if obj is None: return None @@ -123,8 +121,8 @@ def from_dict(cls, obj: Dict) -> Self: "name": obj.get("name"), "nodeCount": obj.get("nodeCount"), "serverType": obj.get("serverType") if obj.get("serverType") is not None else 's0.d1.small', - "sshConfig": SshConfig.from_dict(obj.get("sshConfig")) if obj.get("sshConfig") is not None else None, - "nodes": [Node.from_dict(_item) for _item in obj.get("nodes")] if obj.get("nodes") is not None else None + "sshConfig": SshConfig.from_dict(obj["sshConfig"]) if obj.get("sshConfig") is not None else None, + "nodes": [Node.from_dict(_item) for _item in obj["nodes"]] if obj.get("nodes") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_certificates.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_certificates.py index 99784696..ac4f4dc7 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_certificates.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_certificates.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class RancherClusterCertificates(BaseModel): """ @@ -37,11 +33,11 @@ class RancherClusterCertificates(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["caCertificate", "certificate", "certificateKey"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of RancherClusterCertificates from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of RancherClusterCertificates from a dict""" if obj is None: return None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_config.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_config.py index 67a2524e..37230406 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_config.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_cluster_config.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr -from pydantic import Field from pnap_rancher_solution_api.models.rancher_cluster_certificates import RancherClusterCertificates -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class RancherClusterConfig(BaseModel): """ @@ -42,11 +38,11 @@ class RancherClusterConfig(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["token", "tlsSan", "etcdSnapshotScheduleCron", "etcdSnapshotRetention", "nodeTaint", "clusterDomain", "certificates"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -59,7 +55,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of RancherClusterConfig from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -74,11 +70,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of certificates @@ -92,7 +90,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of RancherClusterConfig from a dict""" if obj is None: return None @@ -107,7 +105,7 @@ def from_dict(cls, obj: Dict) -> Self: "etcdSnapshotRetention": obj.get("etcdSnapshotRetention") if obj.get("etcdSnapshotRetention") is not None else 5, "nodeTaint": obj.get("nodeTaint"), "clusterDomain": obj.get("clusterDomain"), - "certificates": RancherClusterCertificates.from_dict(obj.get("certificates")) if obj.get("certificates") is not None else None + "certificates": RancherClusterCertificates.from_dict(obj["certificates"]) if obj.get("certificates") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_server_metadata.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_server_metadata.py index 2fb74bb9..cb925c71 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_server_metadata.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/rancher_server_metadata.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class RancherServerMetadata(BaseModel): """ @@ -37,11 +33,11 @@ class RancherServerMetadata(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["url", "username", "password"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of RancherServerMetadata from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of RancherServerMetadata from a dict""" if obj is None: return None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/ssh_config.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/ssh_config.py index 64f3f683..c505e98b 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/ssh_config.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/ssh_config.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class SshConfig(BaseModel): """ @@ -37,11 +33,11 @@ class SshConfig(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["installDefaultKeys", "keys", "keyIds"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of SshConfig from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of SshConfig from a dict""" if obj is None: return None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/workload_cluster_config.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/workload_cluster_config.py index fc477b25..1e10c565 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/models/workload_cluster_config.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/models/workload_cluster_config.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictInt, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class WorkloadClusterConfig(BaseModel): """ @@ -33,16 +29,16 @@ class WorkloadClusterConfig(BaseModel): """ # noqa: E501 name: Optional[StrictStr] = Field(default=None, description="The name of the workload cluster. This field is autogenerated if not provided.") server_count: Optional[StrictInt] = Field(default=1, description="Number of configured servers. Currently only server counts of 1 and 3 are possible.", alias="serverCount") - server_type: StrictStr = Field(description="Node server type. Cannot be changed once the cluster is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge` or `d3.g2.c3.xlarge`.", alias="serverType") - location: StrictStr = Field(description="Workload cluster location. Cannot be changed once cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`.") + server_type: StrictStr = Field(description="Node server type. Cannot be changed once the cluster is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge` or `d3.g2.c3.xlarge`.", alias="serverType") + location: StrictStr = Field(description="Workload cluster location. Cannot be changed once cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`.") additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["name", "serverCount", "serverType", "location"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -55,7 +51,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of WorkloadClusterConfig from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -70,11 +66,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -85,7 +83,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of WorkloadClusterConfig from a dict""" if obj is None: return None diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/rest.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/rest.py index a6a990df..d7dea06b 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/rest.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_rancher_solution_api/pnap_rancher_solution_api/version.py b/pnap_rancher_solution_api/pnap_rancher_solution_api/version.py index c756f9c5..09091e00 100644 --- a/pnap_rancher_solution_api/pnap_rancher_solution_api/version.py +++ b/pnap_rancher_solution_api/pnap_rancher_solution_api/version.py @@ -1 +1 @@ -VERSION = "2.0.4" \ No newline at end of file +VERSION = "2.0.5" \ No newline at end of file diff --git a/pnap_rancher_solution_api/pyproject.toml b/pnap_rancher_solution_api/pyproject.toml index ca3414e8..1d5ea4ee 100644 --- a/pnap_rancher_solution_api/pyproject.toml +++ b/pnap_rancher_solution_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_rancher_solution_api" -version = "2.0.4" +version = "2.0.5" description = "Rancher Solution API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Rancher Solution API"] -include = ["pnap_rancher_solution_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_rancher_solution_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_rancher_solution_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_rancher_solution_api/requirements.txt b/pnap_rancher_solution_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_rancher_solution_api/requirements.txt +++ b/pnap_rancher_solution_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_rancher_solution_api/setup.py b/pnap_rancher_solution_api/setup.py index 75b8cc8a..7e24d50a 100644 --- a/pnap_rancher_solution_api/setup.py +++ b/pnap_rancher_solution_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Rancher Solution API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_rancher_solution_api" -VERSION = "2.0.4" -PYTHON_REQUIRES = ">=3.7" +VERSION = "2.0.5" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ Simplify enterprise-grade Kubernetes cluster operations and management with Rancher on Bare Metal Cloud. Deploy Kubernetes clusters using a few API calls.<br> <br> <span class='pnap-api-knowledge-base-link'> Knowledge base articles to help you can be found <a href='https://phoenixnap.com/kb/rancher-bmc-integration-kubernetes' target='_blank'>here</a> </span><br> <br> <b>All URLs are relative to (https://api.phoenixnap.com/solutions/rancher/v1beta)</b> """, # noqa: E501 package_data={"pnap_rancher_solution_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/pnap_tag_api/README.md b/pnap_tag_api/README.md index dcbd973d..b8b2c5ca 100644 --- a/pnap_tag_api/README.md +++ b/pnap_tag_api/README.md @@ -14,13 +14,13 @@ Knowledge base articles to help you can be found This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0 -- Package version: 2.0.4 +- Package version: 2.0.5 - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://phoenixnap.com/](https://phoenixnap.com/) ## Requirements. -Python 3.7+ +Python 3.9+ ## Installation & Usage ### pip install @@ -50,9 +50,16 @@ Then import the package: import pnap_tag_api ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + ```python -import time import pnap_tag_api from pnap_tag_api.rest import ApiException from pprint import pprint @@ -103,6 +110,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints @@ -147,4 +155,3 @@ Authentication schemes defined for the API: ## Author support@phoenixnap.com - diff --git a/pnap_tag_api/docs/DeleteResult.md b/pnap_tag_api/docs/DeleteResult.md index ac918292..9fd7e7cc 100644 --- a/pnap_tag_api/docs/DeleteResult.md +++ b/pnap_tag_api/docs/DeleteResult.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of DeleteResult from a JSON string delete_result_instance = DeleteResult.from_json(json) # print the JSON string representation of the object -print DeleteResult.to_json() +print(DeleteResult.to_json()) # convert the object into a dict delete_result_dict = delete_result_instance.to_dict() # create an instance of DeleteResult from a dict -delete_result_form_dict = delete_result.from_dict(delete_result_dict) +delete_result_from_dict = DeleteResult.from_dict(delete_result_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_tag_api/docs/Error.md b/pnap_tag_api/docs/Error.md index 3b929c90..5b0d23dc 100644 --- a/pnap_tag_api/docs/Error.md +++ b/pnap_tag_api/docs/Error.md @@ -18,12 +18,12 @@ json = "{}" # create an instance of Error from a JSON string error_instance = Error.from_json(json) # print the JSON string representation of the object -print Error.to_json() +print(Error.to_json()) # convert the object into a dict error_dict = error_instance.to_dict() # create an instance of Error from a dict -error_form_dict = error.from_dict(error_dict) +error_from_dict = Error.from_dict(error_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_tag_api/docs/ResourceAssignment.md b/pnap_tag_api/docs/ResourceAssignment.md index 2c24d356..47487364 100644 --- a/pnap_tag_api/docs/ResourceAssignment.md +++ b/pnap_tag_api/docs/ResourceAssignment.md @@ -19,12 +19,12 @@ json = "{}" # create an instance of ResourceAssignment from a JSON string resource_assignment_instance = ResourceAssignment.from_json(json) # print the JSON string representation of the object -print ResourceAssignment.to_json() +print(ResourceAssignment.to_json()) # convert the object into a dict resource_assignment_dict = resource_assignment_instance.to_dict() # create an instance of ResourceAssignment from a dict -resource_assignment_form_dict = resource_assignment.from_dict(resource_assignment_dict) +resource_assignment_from_dict = ResourceAssignment.from_dict(resource_assignment_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_tag_api/docs/Tag.md b/pnap_tag_api/docs/Tag.md index f3dbac67..e08d547a 100644 --- a/pnap_tag_api/docs/Tag.md +++ b/pnap_tag_api/docs/Tag.md @@ -24,12 +24,12 @@ json = "{}" # create an instance of Tag from a JSON string tag_instance = Tag.from_json(json) # print the JSON string representation of the object -print Tag.to_json() +print(Tag.to_json()) # convert the object into a dict tag_dict = tag_instance.to_dict() # create an instance of Tag from a dict -tag_form_dict = tag.from_dict(tag_dict) +tag_from_dict = Tag.from_dict(tag_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_tag_api/docs/TagCreate.md b/pnap_tag_api/docs/TagCreate.md index 93ca9477..04ec212d 100644 --- a/pnap_tag_api/docs/TagCreate.md +++ b/pnap_tag_api/docs/TagCreate.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of TagCreate from a JSON string tag_create_instance = TagCreate.from_json(json) # print the JSON string representation of the object -print TagCreate.to_json() +print(TagCreate.to_json()) # convert the object into a dict tag_create_dict = tag_create_instance.to_dict() # create an instance of TagCreate from a dict -tag_create_form_dict = tag_create.from_dict(tag_create_dict) +tag_create_from_dict = TagCreate.from_dict(tag_create_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_tag_api/docs/TagUpdate.md b/pnap_tag_api/docs/TagUpdate.md index f514ca07..f39a3b6b 100644 --- a/pnap_tag_api/docs/TagUpdate.md +++ b/pnap_tag_api/docs/TagUpdate.md @@ -20,12 +20,12 @@ json = "{}" # create an instance of TagUpdate from a JSON string tag_update_instance = TagUpdate.from_json(json) # print the JSON string representation of the object -print TagUpdate.to_json() +print(TagUpdate.to_json()) # convert the object into a dict tag_update_dict = tag_update_instance.to_dict() # create an instance of TagUpdate from a dict -tag_update_form_dict = tag_update.from_dict(tag_update_dict) +tag_update_from_dict = TagUpdate.from_dict(tag_update_dict) ``` [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pnap_tag_api/docs/TagsApi.md b/pnap_tag_api/docs/TagsApi.md index 16fa8883..0e98131c 100644 --- a/pnap_tag_api/docs/TagsApi.md +++ b/pnap_tag_api/docs/TagsApi.md @@ -23,8 +23,6 @@ Retrieve all tags belonging to the BMC Account. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_tag_api from pnap_tag_api.models.tag import Tag from pnap_tag_api.rest import ApiException @@ -103,8 +101,6 @@ Create a tag with the provided information. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_tag_api from pnap_tag_api.models.tag import Tag from pnap_tag_api.models.tag_create import TagCreate @@ -186,8 +182,6 @@ Delete the tag with the given ID. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_tag_api from pnap_tag_api.models.delete_result import DeleteResult from pnap_tag_api.rest import ApiException @@ -266,8 +260,6 @@ Retrieve the tag with the given ID * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_tag_api from pnap_tag_api.models.tag import Tag from pnap_tag_api.rest import ApiException @@ -346,8 +338,6 @@ Updates the tag with the given ID. * OAuth Authentication (OAuth2): ```python -import time -import os import pnap_tag_api from pnap_tag_api.models.tag import Tag from pnap_tag_api.models.tag_update import TagUpdate diff --git a/pnap_tag_api/pnap_tag_api/__init__.py b/pnap_tag_api/pnap_tag_api/__init__.py index 9b771737..43753856 100644 --- a/pnap_tag_api/pnap_tag_api/__init__.py +++ b/pnap_tag_api/pnap_tag_api/__init__.py @@ -15,26 +15,47 @@ """ # noqa: E501 -__version__ = "2.0.4" +__version__ = "2.0.5" + +# Define package exports +__all__ = [ + "TagsApi", + "ApiResponse", + "ApiClient", + "Configuration", + "OpenApiException", + "ApiTypeError", + "ApiValueError", + "ApiKeyError", + "ApiAttributeError", + "ApiException", + "DeleteResult", + "Error", + "ResourceAssignment", + "Tag", + "TagCreate", + "TagUpdate", +] # import apis into sdk package -from pnap_tag_api.api.tags_api import TagsApi +from pnap_tag_api.api.tags_api import TagsApi as TagsApi # import ApiClient -from pnap_tag_api.api_response import ApiResponse -from pnap_tag_api.api_client import ApiClient -from pnap_tag_api.configuration import Configuration -from pnap_tag_api.exceptions import OpenApiException -from pnap_tag_api.exceptions import ApiTypeError -from pnap_tag_api.exceptions import ApiValueError -from pnap_tag_api.exceptions import ApiKeyError -from pnap_tag_api.exceptions import ApiAttributeError -from pnap_tag_api.exceptions import ApiException +from pnap_tag_api.api_response import ApiResponse as ApiResponse +from pnap_tag_api.api_client import ApiClient as ApiClient +from pnap_tag_api.configuration import Configuration as Configuration +from pnap_tag_api.exceptions import OpenApiException as OpenApiException +from pnap_tag_api.exceptions import ApiTypeError as ApiTypeError +from pnap_tag_api.exceptions import ApiValueError as ApiValueError +from pnap_tag_api.exceptions import ApiKeyError as ApiKeyError +from pnap_tag_api.exceptions import ApiAttributeError as ApiAttributeError +from pnap_tag_api.exceptions import ApiException as ApiException # import models into sdk package -from pnap_tag_api.models.delete_result import DeleteResult -from pnap_tag_api.models.error import Error -from pnap_tag_api.models.resource_assignment import ResourceAssignment -from pnap_tag_api.models.tag import Tag -from pnap_tag_api.models.tag_create import TagCreate -from pnap_tag_api.models.tag_update import TagUpdate +from pnap_tag_api.models.delete_result import DeleteResult as DeleteResult +from pnap_tag_api.models.error import Error as Error +from pnap_tag_api.models.resource_assignment import ResourceAssignment as ResourceAssignment +from pnap_tag_api.models.tag import Tag as Tag +from pnap_tag_api.models.tag_create import TagCreate as TagCreate +from pnap_tag_api.models.tag_update import TagUpdate as TagUpdate + diff --git a/pnap_tag_api/pnap_tag_api/api/tags_api.py b/pnap_tag_api/pnap_tag_api/api/tags_api.py index 43a509da..a7b11cd2 100644 --- a/pnap_tag_api/pnap_tag_api/api/tags_api.py +++ b/pnap_tag_api/pnap_tag_api/api/tags_api.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Tags API @@ -13,29 +11,20 @@ """ # noqa: E501 -import io import warnings - from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt -from typing import Dict, List, Optional, Tuple, Union, Any - -try: - from typing import Annotated -except ImportError: - from typing_extensions import Annotated - -from pydantic import Field +from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated -from pydantic import StrictStr +from pydantic import Field, StrictStr from typing import List, Optional - +from typing_extensions import Annotated from pnap_tag_api.models.delete_result import DeleteResult from pnap_tag_api.models.tag import Tag from pnap_tag_api.models.tag_create import TagCreate from pnap_tag_api.models.tag_update import TagUpdate -from pnap_tag_api.api_client import ApiClient +from pnap_tag_api.api_client import ApiClient, RequestSerialized from pnap_tag_api.api_response import ApiResponse from pnap_tag_api.rest import RESTResponseType @@ -266,7 +255,7 @@ def _tags_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -277,7 +266,9 @@ def _tags_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -292,11 +283,12 @@ def _tags_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -541,7 +533,7 @@ def _tags_post_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -552,7 +544,9 @@ def _tags_post_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -565,11 +559,12 @@ def _tags_post_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: @@ -821,7 +816,7 @@ def _tags_tag_id_delete_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -832,7 +827,9 @@ def _tags_tag_id_delete_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -845,11 +842,12 @@ def _tags_tag_id_delete_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1088,7 +1086,7 @@ def _tags_tag_id_get_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1099,7 +1097,9 @@ def _tags_tag_id_get_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1112,11 +1112,12 @@ def _tags_tag_id_get_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # authentication setting @@ -1371,7 +1372,7 @@ def _tags_tag_id_patch_serialize( _content_type, _headers, _host_index, - ) -> Tuple: + ) -> RequestSerialized: _host = None @@ -1382,7 +1383,9 @@ def _tags_tag_id_patch_serialize( _query_params: List[Tuple[str, str]] = [] _header_params: Dict[str, Optional[str]] = _headers or {} _form_params: List[Tuple[str, str]] = [] - _files: Dict[str, str] = {} + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} _body_params: Optional[bytes] = None # process the path parameters @@ -1397,11 +1400,12 @@ def _tags_tag_id_patch_serialize( # set the HTTP header `Accept` - _header_params['Accept'] = self.api_client.select_header_accept( - [ - 'application/json' - ] - ) + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) # set the HTTP header `Content-Type` if _content_type: diff --git a/pnap_tag_api/pnap_tag_api/api_client.py b/pnap_tag_api/pnap_tag_api/api_client.py index 699c08c2..f5c79a75 100644 --- a/pnap_tag_api/pnap_tag_api/api_client.py +++ b/pnap_tag_api/pnap_tag_api/api_client.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Tags API @@ -13,20 +11,24 @@ """ # noqa: E501 -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr from pnap_tag_api.configuration import Configuration -from pnap_tag_api.api_response import ApiResponse +from pnap_tag_api.api_response import ApiResponse, T as ApiResponseT import pnap_tag_api.models from pnap_tag_api import rest from pnap_tag_api.exceptions import ( @@ -39,6 +41,7 @@ ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -65,6 +68,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -87,11 +91,11 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = f"PNAP-python-sdk-bmc/pnap_tag_api/2.0.4" + self.user_agent = f"PNAP-python-sdk-bmc/pnap_tag_api/2.0.5" self.client_side_validation = configuration.client_side_validation # Set default X-Powered-By. - self.powered_by = f"PNAP-python-sdk-bmc/pnap_tag_api/2.0.4" + self.powered_by = f"PNAP-python-sdk-bmc/pnap_tag_api/2.0.5" def __enter__(self): return self @@ -99,23 +103,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): pass - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value - @property def user_agent(self): """User agent for this API client""" @@ -168,7 +155,7 @@ def param_serialize( collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -227,7 +214,8 @@ def param_serialize( post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -245,7 +233,7 @@ def param_serialize( body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -294,23 +282,23 @@ def call_api( ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -327,12 +315,12 @@ 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -344,7 +332,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 ) @@ -352,9 +340,11 @@ def sanitize_for_serialization(self, obj): """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -364,8 +354,14 @@ def sanitize_for_serialization(self, obj): """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -376,6 +372,8 @@ def sanitize_for_serialization(self, 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 @@ -385,28 +383,49 @@ def sanitize_for_serialization(self, obj): # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -423,12 +442,16 @@ def __deserialize(self, data, klass): if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -440,12 +463,16 @@ 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: return self.__deserialize_model(data, klass) @@ -456,7 +483,7 @@ def parameters_to_tuples(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -486,7 +513,7 @@ def parameters_to_url_query(self, params, collection_formats): :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -500,7 +527,7 @@ def parameters_to_url_query(self, params, collection_formats): if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -516,33 +543,41 @@ def parameters_to_url_query(self, params, collection_formats): else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -669,12 +704,16 @@ 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: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -741,6 +780,24 @@ def __deserialize_datetime(self, string): ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/pnap_tag_api/pnap_tag_api/api_response.py b/pnap_tag_api/pnap_tag_api/api_response.py index 2ac1ada6..9bc7c11f 100644 --- a/pnap_tag_api/pnap_tag_api/api_response.py +++ b/pnap_tag_api/pnap_tag_api/api_response.py @@ -1,8 +1,8 @@ """API response object.""" from __future__ import annotations -from typing import Any, Dict, Optional, Generic, TypeVar -from pydantic import Field, StrictInt, StrictStr, StrictBytes, BaseModel +from typing import Optional, Generic, Mapping, TypeVar +from pydantic import Field, StrictInt, StrictBytes, BaseModel T = TypeVar("T") @@ -12,7 +12,7 @@ class ApiResponse(BaseModel, Generic[T]): """ status_code: StrictInt = Field(description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field(None, description="HTTP headers") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") data: T = Field(description="Deserialized data given the data type") raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") diff --git a/pnap_tag_api/pnap_tag_api/configuration.py b/pnap_tag_api/pnap_tag_api/configuration.py index e78828d9..680f339a 100644 --- a/pnap_tag_api/pnap_tag_api/configuration.py +++ b/pnap_tag_api/pnap_tag_api/configuration.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Tags API @@ -14,12 +12,16 @@ import copy +import http.client as httplib import logging +from logging import FileHandler import multiprocessing import sys +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union +from typing_extensions import NotRequired, Self + import urllib3 -import http.client as httplib JSON_SCHEMA_VALIDATION_KEYWORDS = { 'multipleOf', 'maximum', 'exclusiveMaximum', @@ -27,10 +29,114 @@ 'minLength', 'pattern', 'maxItems', 'minItems' } +ServerVariablesT = Dict[str, str] + +GenericAuthSetting = TypedDict( + "GenericAuthSetting", + { + "type": str, + "in": str, + "key": str, + "value": str, + }, +) + + +OAuth2AuthSetting = TypedDict( + "OAuth2AuthSetting", + { + "type": Literal["oauth2"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +APIKeyAuthSetting = TypedDict( + "APIKeyAuthSetting", + { + "type": Literal["api_key"], + "in": str, + "key": str, + "value": Optional[str], + }, +) + + +BasicAuthSetting = TypedDict( + "BasicAuthSetting", + { + "type": Literal["basic"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": Optional[str], + }, +) + + +BearerFormatAuthSetting = TypedDict( + "BearerFormatAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "format": Literal["JWT"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +BearerAuthSetting = TypedDict( + "BearerAuthSetting", + { + "type": Literal["bearer"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": str, + }, +) + + +HTTPSignatureAuthSetting = TypedDict( + "HTTPSignatureAuthSetting", + { + "type": Literal["http-signature"], + "in": Literal["header"], + "key": Literal["Authorization"], + "value": None, + }, +) + + +AuthSettings = TypedDict( + "AuthSettings", + { + "OAuth2": OAuth2AuthSetting, + }, + total=False, +) + + +class HostSettingVariable(TypedDict): + description: str + default_value: str + enum_values: List[str] + + +class HostSetting(TypedDict): + url: str + description: str + variables: NotRequired[Dict[str, HostSettingVariable]] + + class Configuration: """This class contains various settings of the API client. :param host: Base url. + :param ignore_operation_servers + Boolean to ignore operation servers for the API client. + Config will use `host` as the base url regardless of the operation servers. :param api_key: Dict to store API key(s). Each entry in the dict specifies an API key. The dict key is the name of the security scheme in the OAS specification. @@ -53,20 +159,38 @@ class Configuration: values before. :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. + :param retries: int | urllib3.util.retry.Retry - Retry configuration. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. + :param cert_file: the path to a client certificate file, for mTLS. + :param key_file: the path to a client key file, for mTLS. :Example: """ - _default = None - - def __init__(self, host=None, - api_key=None, api_key_prefix=None, - username=None, password=None, - access_token=None, - server_index=None, server_variables=None, - server_operation_index=None, server_operation_variables=None, - ssl_ca_cert=None, - ) -> None: + _default: ClassVar[Optional[Self]] = None + + def __init__( + self, + host: Optional[str]=None, + api_key: Optional[Dict[str, str]]=None, + api_key_prefix: Optional[Dict[str, str]]=None, + username: Optional[str]=None, + password: Optional[str]=None, + access_token: Optional[str]=None, + server_index: Optional[int]=None, + server_variables: Optional[ServerVariablesT]=None, + server_operation_index: Optional[Dict[int, int]]=None, + server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, + ignore_operation_servers: bool=False, + ssl_ca_cert: Optional[str]=None, + retries: Optional[Union[int, Any]] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, + cert_file: Optional[str]=None, + key_file: Optional[str]=None, + *, + debug: Optional[bool] = None, + ) -> None: """Constructor """ self._base_path = "https://api.phoenixnap.com/tag-manager/v1" if host is None else host @@ -80,6 +204,9 @@ def __init__(self, host=None, self.server_operation_variables = server_operation_variables or {} """Default server variables """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ self.temp_folder_path = None """Temp file folder for downloading files """ @@ -117,13 +244,16 @@ def __init__(self, host=None, self.logger_stream_handler = None """Log stream handler """ - self.logger_file_handler = None + self.logger_file_handler: Optional[FileHandler] = None """Log file handler """ self.logger_file = None """Debug file location """ - self.debug = False + if debug is not None: + self.debug = debug + else: + self.__debug = False """Debug switch """ @@ -135,10 +265,14 @@ def __init__(self, host=None, self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ - self.cert_file = None + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ + self.cert_file = cert_file """client certificate file """ - self.key_file = None + self.key_file = key_file """client key file """ self.assert_hostname = None @@ -157,7 +291,7 @@ def __init__(self, host=None, cpu_count * 5 is used as default value to increase performance. """ - self.proxy = None + self.proxy: Optional[str] = None """Proxy URL """ self.proxy_headers = None @@ -166,8 +300,8 @@ def __init__(self, host=None, self.safe_chars_for_path_param = '' """Safe chars for path_param """ - self.retries = None - """Adding retries to override urllib3 default value 3 + self.retries = retries + """Retry configuration """ # Enable client side validation self.client_side_validation = True @@ -184,7 +318,7 @@ def __init__(self, host=None, """date format """ - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: Dict[int, Any]) -> Self: cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result @@ -198,11 +332,11 @@ def __deepcopy__(self, memo): result.debug = self.debug return result - def __setattr__(self, name, value): + def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) @classmethod - def set_default(cls, default): + def set_default(cls, default: Optional[Self]) -> None: """Set default instance of configuration. It stores default configuration, which can be @@ -213,7 +347,7 @@ def set_default(cls, default): cls._default = default @classmethod - def get_default_copy(cls): + def get_default_copy(cls) -> Self: """Deprecated. Please use `get_default` instead. Deprecated. Please use `get_default` instead. @@ -223,7 +357,7 @@ def get_default_copy(cls): return cls.get_default() @classmethod - def get_default(cls): + def get_default(cls) -> Self: """Return the default configuration. This method returns newly created, based on default constructor, @@ -233,11 +367,11 @@ def get_default(cls): :return: The configuration object. """ if cls._default is None: - cls._default = Configuration() + cls._default = cls() return cls._default @property - def logger_file(self): + def logger_file(self) -> Optional[str]: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -249,7 +383,7 @@ def logger_file(self): return self.__logger_file @logger_file.setter - def logger_file(self, value): + def logger_file(self, value: Optional[str]) -> None: """The logger file. If the logger_file is None, then add stream handler and remove file @@ -268,7 +402,7 @@ def logger_file(self, value): logger.addHandler(self.logger_file_handler) @property - def debug(self): + def debug(self) -> bool: """Debug status :param value: The debug status, True or False. @@ -277,7 +411,7 @@ def debug(self): return self.__debug @debug.setter - def debug(self, value): + def debug(self, value: bool) -> None: """Debug status :param value: The debug status, True or False. @@ -299,7 +433,7 @@ def debug(self, value): httplib.HTTPConnection.debuglevel = 0 @property - def logger_format(self): + def logger_format(self) -> str: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -310,7 +444,7 @@ def logger_format(self): return self.__logger_format @logger_format.setter - def logger_format(self, value): + def logger_format(self, value: str) -> None: """The logger format. The logger_formatter will be updated when sets logger_format. @@ -321,7 +455,7 @@ def logger_format(self, value): self.__logger_format = value self.logger_formatter = logging.Formatter(self.__logger_format) - def get_api_key_with_prefix(self, identifier, alias=None): + def get_api_key_with_prefix(self, identifier: str, alias: Optional[str]=None) -> Optional[str]: """Gets API key (with prefix if set). :param identifier: The identifier of apiKey. @@ -338,7 +472,9 @@ def get_api_key_with_prefix(self, identifier, alias=None): else: return key - def get_basic_auth_token(self): + return None + + def get_basic_auth_token(self) -> Optional[str]: """Gets HTTP basic authentication header (string). :return: The token for basic HTTP authentication. @@ -349,16 +485,17 @@ def get_basic_auth_token(self): password = "" if self.password is not None: password = self.password + return urllib3.util.make_headers( basic_auth=username + ':' + password ).get('authorization') - def auth_settings(self): + def auth_settings(self)-> AuthSettings: """Gets Auth Settings dict for api client. :return: The Auth Settings information dict. """ - auth = {} + auth: AuthSettings = {} if self.access_token is not None: auth['OAuth2'] = { 'type': 'oauth2', @@ -368,7 +505,7 @@ def auth_settings(self): } return auth - def to_debug_report(self): + def to_debug_report(self) -> str: """Gets the essential information for debugging. :return: The report for debugging. @@ -377,10 +514,10 @@ def to_debug_report(self): "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0\n"\ - "SDK Package Version: 2.0.4".\ + "SDK Package Version: 2.0.5".\ format(env=sys.platform, pyversion=sys.version) - def get_host_settings(self): + def get_host_settings(self) -> List[HostSetting]: """Gets an array of host settings :return: An array of host settings @@ -392,7 +529,12 @@ def get_host_settings(self): } ] - def get_host_from_settings(self, index, variables=None, servers=None): + def get_host_from_settings( + self, + index: Optional[int], + variables: Optional[ServerVariablesT]=None, + servers: Optional[List[HostSetting]]=None, + ) -> str: """Gets host URL based on the index and variables :param index: array index of the host settings :param variables: hash of variable and the corresponding value @@ -420,6 +562,7 @@ def get_host_from_settings(self, index, variables=None, servers=None): variable_name, variable['default_value']) if 'enum_values' in variable \ + and variable['enum_values'] \ and used_value not in variable['enum_values']: raise ValueError( "The variable `{0}` in the host URL has invalid value " @@ -432,12 +575,12 @@ def get_host_from_settings(self, index, variables=None, servers=None): return url @property - def host(self): + def host(self) -> str: """Return generated host.""" return self.get_host_from_settings(self.server_index, variables=self.server_variables) @host.setter - def host(self, value): + def host(self, value: str) -> None: """Fix base path.""" self._base_path = value self.server_index = None diff --git a/pnap_tag_api/pnap_tag_api/exceptions.py b/pnap_tag_api/pnap_tag_api/exceptions.py index ef397fea..0e55e519 100644 --- a/pnap_tag_api/pnap_tag_api/exceptions.py +++ b/pnap_tag_api/pnap_tag_api/exceptions.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Tags API @@ -12,8 +10,8 @@ Do not edit the class manually. """ # noqa: E501 -from typing import Any, Optional +from typing import Any, Optional from typing_extensions import Self class OpenApiException(Exception): @@ -130,7 +128,7 @@ def __init__( self.body = http_resp.data.decode('utf-8') except Exception: pass - self.headers = http_resp.getheaders() + self.headers = http_resp.headers @classmethod def from_response( @@ -152,6 +150,13 @@ def from_response( if http_resp.status == 404: raise NotFoundException(http_resp=http_resp, body=body, data=data) + # Added new conditions for 409 and 422 + if http_resp.status == 409: + raise ConflictException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 422: + raise UnprocessableEntityException(http_resp=http_resp, body=body, data=data) + if 500 <= http_resp.status <= 599: raise ServiceException(http_resp=http_resp, body=body, data=data) raise ApiException(http_resp=http_resp, body=body, data=data) @@ -164,8 +169,11 @@ def __str__(self): error_message += "HTTP response headers: {0}\n".format( self.headers) - if self.data or self.body: - error_message += "HTTP response body: {0}\n".format(self.data or self.body) + if self.body: + error_message += "HTTP response body: {0}\n".format(self.body) + + if self.data: + error_message += "HTTP response data: {0}\n".format(self.data) return error_message @@ -190,6 +198,16 @@ class ServiceException(ApiException): pass +class ConflictException(ApiException): + """Exception for HTTP 409 Conflict.""" + pass + + +class UnprocessableEntityException(ApiException): + """Exception for HTTP 422 Unprocessable Entity.""" + pass + + def render_path(path_to_item): """Returns a string representation of a path""" result = "" diff --git a/pnap_tag_api/pnap_tag_api/models/__init__.py b/pnap_tag_api/pnap_tag_api/models/__init__.py index 3b0de625..ce3230f0 100644 --- a/pnap_tag_api/pnap_tag_api/models/__init__.py +++ b/pnap_tag_api/pnap_tag_api/models/__init__.py @@ -13,7 +13,6 @@ Do not edit the class manually. """ # noqa: E501 - # import models into model package from pnap_tag_api.models.delete_result import DeleteResult from pnap_tag_api.models.error import Error @@ -21,3 +20,4 @@ from pnap_tag_api.models.tag import Tag from pnap_tag_api.models.tag_create import TagCreate from pnap_tag_api.models.tag_update import TagUpdate + diff --git a/pnap_tag_api/pnap_tag_api/models/delete_result.py b/pnap_tag_api/pnap_tag_api/models/delete_result.py index dd900078..b38b795f 100644 --- a/pnap_tag_api/pnap_tag_api/models/delete_result.py +++ b/pnap_tag_api/pnap_tag_api/models/delete_result.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class DeleteResult(BaseModel): """ @@ -36,11 +32,11 @@ class DeleteResult(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["result", "tagId"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of DeleteResult from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of DeleteResult from a dict""" if obj is None: return None diff --git a/pnap_tag_api/pnap_tag_api/models/error.py b/pnap_tag_api/pnap_tag_api/models/error.py index 3a41eacf..f7cc2da6 100644 --- a/pnap_tag_api/pnap_tag_api/models/error.py +++ b/pnap_tag_api/pnap_tag_api/models/error.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Error(BaseModel): """ @@ -36,11 +32,11 @@ class Error(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["message", "validationErrors"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Error from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Error from a dict""" if obj is None: return None diff --git a/pnap_tag_api/pnap_tag_api/models/resource_assignment.py b/pnap_tag_api/pnap_tag_api/models/resource_assignment.py index df7f4020..2d9fcf87 100644 --- a/pnap_tag_api/pnap_tag_api/models/resource_assignment.py +++ b/pnap_tag_api/pnap_tag_api/models/resource_assignment.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class ResourceAssignment(BaseModel): """ @@ -36,11 +32,11 @@ class ResourceAssignment(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["resourceName", "value"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -53,7 +49,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of ResourceAssignment from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -68,11 +64,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -83,7 +81,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of ResourceAssignment from a dict""" if obj is None: return None diff --git a/pnap_tag_api/pnap_tag_api/models/tag.py b/pnap_tag_api/pnap_tag_api/models/tag.py index 3e99afce..97c37a6f 100644 --- a/pnap_tag_api/pnap_tag_api/models/tag.py +++ b/pnap_tag_api/pnap_tag_api/models/tag.py @@ -18,15 +18,11 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr, field_validator -from pydantic import Field from pnap_tag_api.models.resource_assignment import ResourceAssignment -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class Tag(BaseModel): """ @@ -48,15 +44,15 @@ def created_by_validate_enum(cls, value): if value is None: return value - if value not in ('USER', 'SYSTEM'): + if value not in set(['USER', 'SYSTEM']): raise ValueError("must be one of enum values ('USER', 'SYSTEM')") return value - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -69,7 +65,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of Tag from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -84,19 +80,21 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # override the default output from pydantic by calling `to_dict()` of each item in resource_assignments (list) _items = [] if self.resource_assignments: - for _item in self.resource_assignments: - if _item: - _items.append(_item.to_dict()) + for _item_resource_assignments in self.resource_assignments: + if _item_resource_assignments: + _items.append(_item_resource_assignments.to_dict()) _dict['resourceAssignments'] = _items # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: @@ -106,7 +104,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of Tag from a dict""" if obj is None: return None @@ -120,7 +118,7 @@ def from_dict(cls, obj: Dict) -> Self: "values": obj.get("values"), "description": obj.get("description"), "isBillingTag": obj.get("isBillingTag"), - "resourceAssignments": [ResourceAssignment.from_dict(_item) for _item in obj.get("resourceAssignments")] if obj.get("resourceAssignments") is not None else None, + "resourceAssignments": [ResourceAssignment.from_dict(_item) for _item in obj["resourceAssignments"]] if obj.get("resourceAssignments") is not None else None, "createdBy": obj.get("createdBy") if obj.get("createdBy") is not None else 'USER' }) # store additional fields in additional_properties diff --git a/pnap_tag_api/pnap_tag_api/models/tag_create.py b/pnap_tag_api/pnap_tag_api/models/tag_create.py index 8c75f656..04056cf7 100644 --- a/pnap_tag_api/pnap_tag_api/models/tag_create.py +++ b/pnap_tag_api/pnap_tag_api/models/tag_create.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagCreate(BaseModel): """ @@ -37,11 +33,11 @@ class TagCreate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["name", "description", "isBillingTag"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagCreate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagCreate from a dict""" if obj is None: return None diff --git a/pnap_tag_api/pnap_tag_api/models/tag_update.py b/pnap_tag_api/pnap_tag_api/models/tag_update.py index 5fecdd8e..a79f9571 100644 --- a/pnap_tag_api/pnap_tag_api/models/tag_update.py +++ b/pnap_tag_api/pnap_tag_api/models/tag_update.py @@ -18,14 +18,10 @@ import re # noqa: F401 import json - +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool, StrictStr -from pydantic import Field -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Optional, Set +from typing_extensions import Self class TagUpdate(BaseModel): """ @@ -37,11 +33,11 @@ class TagUpdate(BaseModel): additional_properties: Dict[str, Any] = {} __properties: ClassVar[List[str]] = ["name", "description", "isBillingTag"] - model_config = { - "populate_by_name": True, - "validate_assignment": True, - "protected_namespaces": (), - } + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) def to_str(self) -> str: @@ -54,7 +50,7 @@ def to_json(self) -> str: return json.dumps(self.to_dict()) @classmethod - def from_json(cls, json_str: str) -> Self: + def from_json(cls, json_str: str) -> Optional[Self]: """Create an instance of TagUpdate from a JSON string""" return cls.from_dict(json.loads(json_str)) @@ -69,11 +65,13 @@ def to_dict(self) -> Dict[str, Any]: are ignored. * Fields in `self.additional_properties` are added to the output dict. """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + _dict = self.model_dump( by_alias=True, - exclude={ - "additional_properties", - }, + exclude=excluded_fields, exclude_none=True, ) # puts key-value pairs in additional_properties in the top level @@ -84,7 +82,7 @@ def to_dict(self) -> Dict[str, Any]: return _dict @classmethod - def from_dict(cls, obj: Dict) -> Self: + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: """Create an instance of TagUpdate from a dict""" if obj is None: return None diff --git a/pnap_tag_api/pnap_tag_api/rest.py b/pnap_tag_api/pnap_tag_api/rest.py index c19bf673..f8e9f461 100644 --- a/pnap_tag_api/pnap_tag_api/rest.py +++ b/pnap_tag_api/pnap_tag_api/rest.py @@ -49,12 +49,17 @@ def read(self): self.data = self.response.data 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) @@ -72,56 +77,46 @@ def __init__(self, configuration) -> None: else: cert_reqs = ssl.CERT_NONE - addition_pool_args = {} + pool_args = { + "cert_reqs": cert_reqs, + "ca_certs": configuration.ssl_ca_cert, + "cert_file": configuration.cert_file, + "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, + } if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = ( + pool_args['assert_hostname'] = ( configuration.assert_hostname ) if configuration.retries is not None: - addition_pool_args['retries'] = configuration.retries + pool_args['retries'] = configuration.retries if configuration.tls_server_name: - addition_pool_args['server_hostname'] = configuration.tls_server_name + pool_args['server_hostname'] = configuration.tls_server_name if configuration.socket_options is not None: - addition_pool_args['socket_options'] = configuration.socket_options + pool_args['socket_options'] = configuration.socket_options if configuration.connection_pool_maxsize is not None: - addition_pool_args['maxsize'] = configuration.connection_pool_maxsize + pool_args['maxsize'] = configuration.connection_pool_maxsize # https pool manager + self.pool_manager: urllib3.PoolManager + if configuration.proxy: if is_socks_proxy_url(configuration.proxy): from urllib3.contrib.socks import SOCKSProxyManager - self.pool_manager = SOCKSProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["headers"] = configuration.proxy_headers + self.pool_manager = SOCKSProxyManager(**pool_args) else: - self.pool_manager = urllib3.ProxyManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) + pool_args["proxy_url"] = configuration.proxy + pool_args["proxy_headers"] = configuration.proxy_headers + self.pool_manager = urllib3.ProxyManager(**pool_args) else: - self.pool_manager = urllib3.PoolManager( - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) + self.pool_manager = urllib3.PoolManager(**pool_args) def request( self, @@ -214,6 +209,8 @@ def request( # Content-Type which generated by urllib3 will be # overwritten. del headers['Content-Type'] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a,b) for a, b in post_params] r = self.pool_manager.request( method, url, @@ -224,19 +221,18 @@ def request( preload_content=False ) # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form + # other content types than JSON when `body` argument is + # provided in serialized form. elif isinstance(body, str) or isinstance(body, bytes): - request_body = body r = self.pool_manager.request( method, url, - body=request_body, + body=body, timeout=timeout, headers=headers, preload_content=False ) - elif headers['Content-Type'] == 'text/plain' and isinstance(body, bool): + elif headers['Content-Type'].startswith('text/') and isinstance(body, bool): request_body = "true" if body else "false" r = self.pool_manager.request( method, diff --git a/pnap_tag_api/pnap_tag_api/version.py b/pnap_tag_api/pnap_tag_api/version.py index c756f9c5..09091e00 100644 --- a/pnap_tag_api/pnap_tag_api/version.py +++ b/pnap_tag_api/pnap_tag_api/version.py @@ -1 +1 @@ -VERSION = "2.0.4" \ No newline at end of file +VERSION = "2.0.5" \ No newline at end of file diff --git a/pnap_tag_api/pyproject.toml b/pnap_tag_api/pyproject.toml index 0e854698..3623e2b9 100644 --- a/pnap_tag_api/pyproject.toml +++ b/pnap_tag_api/pyproject.toml @@ -1,30 +1,95 @@ -[tool.poetry] +[project] name = "pnap_tag_api" -version = "2.0.4" +version = "2.0.5" description = "Tags API" -authors = ["PhoenixNAP Team "] -license = "Apache 2.0" +authors = [ + {name = "PhoenixNAP Team",email = "support@phoenixnap.com"}, +] +license = { text = "Apache 2.0" } readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "Tags API"] -include = ["pnap_tag_api/py.typed"] +requires-python = ">=3.9" + +dependencies = [ + "urllib3 (>=2.1.0,<3.0.0)", + "python-dateutil (>=2.8.2)", + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +] + +[project.urls] +Repository = "https://github.com/GIT_USER_ID/GIT_REPO_ID" -[tool.poetry.dependencies] -python = "^3.7" +[tool.poetry] +requires-poetry = ">=2.0" -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" -pydantic = ">=2" -typing-extensions = ">=4.7.1" +[tool.poetry.group.dev.dependencies] +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" -[tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "pnap_tag_api", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "pnap_tag_api.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/pnap_tag_api/requirements.txt b/pnap_tag_api/requirements.txt index cc85509e..6cbb2b98 100644 --- a/pnap_tag_api/requirements.txt +++ b/pnap_tag_api/requirements.txt @@ -1,5 +1,4 @@ -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.25.3, < 2.1.0 +urllib3 >= 2.1.0, < 3.0.0 +python_dateutil >= 2.8.2 pydantic >= 2 typing-extensions >= 4.7.1 diff --git a/pnap_tag_api/setup.py b/pnap_tag_api/setup.py index 39a9fd7b..8d9a251f 100644 --- a/pnap_tag_api/setup.py +++ b/pnap_tag_api/setup.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ Tags API @@ -22,11 +20,11 @@ # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools NAME = "pnap_tag_api" -VERSION = "2.0.4" -PYTHON_REQUIRES = ">=3.7" +VERSION = "2.0.5" +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", + "urllib3 >= 2.1.0, < 3.0.0", + "python-dateutil >= 2.8.2", "pydantic >= 2", "typing-extensions >= 4.7.1", ] @@ -48,4 +46,4 @@ Tags are case-sensitive key-value pairs that simplify resource management. The Tag Manager API allows you to create and manage such tags to later assign them to related resources in your Bare Metal Cloud (through the respective resource apis) in order to group and categorize them.<br> <br> <span class='pnap-api-knowledge-base-link'> Knowledge base articles to help you can be found <a href='https://phoenixnap.com/kb/bmc-server-management-via-api#server-tag-manager-api' target='_blank'>here</a> </span><br> <br> <b>All URLs are relative to (https://api.phoenixnap.com/tag-manager/v1/)</b> """, # noqa: E501 package_data={"pnap_tag_api": ["py.typed"]}, -) +) \ No newline at end of file diff --git a/specs/pnap_bmc_api.spec.yaml b/specs/pnap_bmc_api.spec.yaml index 49d070ef..25acb9df 100644 --- a/specs/pnap_bmc_api.spec.yaml +++ b/specs/pnap_bmc_api.spec.yaml @@ -496,18 +496,21 @@ paths: - 10.0.0.2 dhcp: false statusDescription: in-progress + vlanId: 10 DhcpTrue: value: id: 60473a6115e34466c9f8f083 ips: [] dhcp: true statusDescription: in-progress + vlanId: 10 DhcpFalseIpsEmptyForceTrue: value: id: 60473a6115e34466c9f8f083 ips: [] dhcp: false statusDescription: in-progress + vlanId: 10 '400': $ref: '#/components/responses/BadRequest' '401': @@ -560,10 +563,16 @@ paths: ips: - 10.0.0.1 - 10.0.0.2 + dhcp: false + statusDescription: assigned + vlanId: 10 privateNetworkWithoutIpsForceTrue: value: id: 60473a6115e34466c9f8f083 ips: [] + dhcp: false + statusDescription: assigned + vlanId: 10 '400': $ref: '#/components/responses/BadRequest' '401': @@ -645,6 +654,28 @@ paths: application/json: schema: $ref: '#/components/schemas/ServerPublicNetwork' + examples: + PublicNetworkWithProvidedIps: + value: + id: 60473c2509268bc77fd06d29 + ips: + - 182.16.0.146 + - 182.16.0.147 + statusDescription: in-progress + vlanId: 10 + PublicNetworkWithNoIpsAndForceTrue: + value: + id: 60473c2509268bc77fd06d29 + ips: [] + statusDescription: in-progress + vlanId: 10 + PublicNetworkWithIpV6AndComputeSlaacIpTrue: + value: + id: 60473c2509268bc77fd06d29 + ips: + - 2001:db8::f + statusDescription: in-progress + vlanId: 10 '400': $ref: '#/components/responses/BadRequest' '401': @@ -709,6 +740,7 @@ paths: - 182.16.0.147 - 2001:db8::b statusDescription: assigned + vlanId: 10 PublicNetworkWithProvidedIpsAndRanges: value: id: 60473a6115e34466c9f8f088 @@ -718,11 +750,13 @@ paths: - 2001:db8::f - 2001:db8::b - 2001:db8::d statusDescription: assigned + vlanId: 10 PublicNetworkWithNoIpsAndForceTrue: value: id: 60473a6115e34466c9f8f088 ips: [] statusDescription: assigned + vlanId: 10 '400': $ref: '#/components/responses/BadRequest' '401': @@ -1111,6 +1145,43 @@ paths: $ref: '#/components/responses/Conflict' '500': $ref: '#/components/responses/InternalServerError' + /servers/{serverId}/actions/transfer-reservation: + parameters: + - $ref: '#/components/parameters/serverIdPathParam' + post: + tags: + - Servers + description: Transfer server reservation. An active (READY) reservation can be transferred from a server in ERROR or RESERVED status to another HOURLY provisioned server of the same location and type. + summary: Transfer server reservation. + operationId: serversServerIdActionsTransferReservation + security: + - OAuth2: + - bmc + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ReservationTransferDetails' + example: + targetServerId: 54a21648dasda4s9843a17 + responses: + '200': + description: The server reservation has been successfully transferred. + content: + application/json: + schema: + $ref: '#/components/schemas/Server' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '409': + $ref: '#/components/responses/Conflict' + '500': + $ref: '#/components/responses/InternalServerError' /ssh-keys: post: tags: @@ -1487,6 +1558,14 @@ components: - 172.217.22.14 - 10.111.14.40/29 - 10.111.14.66 - 10.111.14.71 + bringYourOwnLicense: + description: | + Use a Bring Your Own (BYO) Windows license. + If true, the server is provisioned in trial mode, and you must activate your own license. + If false (default), the server includes a managed Windows license billed by the platform. + type: boolean + example: false + default: false rootPassword: description: (Read-only) Auto-generated password set for user 'root' on an ESXi or Proxmox server.
The password is not stored and therefore will only be returned in response to provisioning a server. Copy and save it for future reference. readOnly: true @@ -1546,7 +1625,7 @@ components: - 10.1.1.1 - 10.1.1.20 - 10.1.1.25 dhcp: - description: Determines whether DHCP is enabled for this server. Should be false if any IPs are provided. Not supported for Proxmox OS. + description: 'Determines whether DHCP is enabled for this server.
The following restrictions apply when enabling DHCP:
  • DHCP support is limited to servers configured exclusively with private networks (PRIVATE_ONLY).
  • DHCP value needs to be consistent across all server-configured private networks.
  • The server does not support manual gateway address configuration.
  • Private IP addresses for network cannot be specified.
Note: Not supported on Proxmox OS.' type: boolean default: false example: false @@ -1555,6 +1634,11 @@ components: readOnly: true type: string example: assigned + vlanId: + description: (Read-only) The VLAN on which this network has been configured within the network switch. + readOnly: true + type: integer + example: 10 PrivateNetworkConfiguration: type: object description: Private network details of bare metal server. @@ -1571,7 +1655,7 @@ components: default: USE_OR_CREATE_DEFAULT example: USER_DEFINED privateNetworks: - description: The list of private networks this server is member of. When this field is part of request body, it'll be used to specify the private networks to assign to this server upon provisioning. Used alongside the `USER_DEFINED` configurationType. + description: The list of private networks this server belongs to. If this field is part of a request body, it will be used for specifying the private networks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType. type: array items: $ref: '#/components/schemas/ServerPrivateNetwork' @@ -1614,7 +1698,7 @@ components: - NONE default: PURCHASE_NEW ipBlocks: - description: Used to specify the previously purchased IP blocks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType. + description: Used for specifying the previously purchased IPv4 blocks to assign to this server upon provisioning. Used alongside the USER_DEFINED configurationType. type: array maxItems: 1 items: @@ -1630,16 +1714,20 @@ components: type: string example: 60473c2509268bc77fd06d29 ips: - description: Configurable/configured IPs on the server.
At least 1 IP address is required. Valid IP format is single IP addresses. All IPs must be within the network's range.
Setting the `computeSlaacIp` field to `true` allows you to provide an empty array of IPs.
Additionally, setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
+ description: Configurable/configured IPs on the server.
At least 1 IP address is required. Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). All IPs must be within the network's range.
Setting the `computeSlaacIp` field to `true` allows you to provide an empty array of IPs.
Additionally, setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs. Note that at least one IP is required for the gateway address to be selected from this network.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
type: array items: type: string example: - 182.16.0.146 - - 2001:db8::b + - 10.1.1.20 - 10.1.1.25 + - 2001:db8::f + - 2001:db8::b - 2001:db8::d example: - 182.16.0.146 - - 2001:db8::b + - 10.1.1.20 - 10.1.1.25 + - 2001:db8::f + - 2001:db8::b - 2001:db8::d statusDescription: description: (Read-only) The status of the assignment to the network. readOnly: true @@ -1650,12 +1738,17 @@ components: writeOnly: true type: boolean example: true + vlanId: + description: (Read-only) The VLAN on which this network has been configured within the network switch. + readOnly: true + type: integer + example: 10 PublicNetworkConfiguration: type: object description: Public network details of bare metal server. properties: publicNetworks: - description: The list of public networks this server is member of. When this field is part of request body, it'll be used to specify the public networks to assign to this server upon provisioning. + description: The list of public networks this server belongs to. If this field is part of a request body, it will be used for specifying the public networks to assign to this server on provision. Only IPv4 addresses can be specified. type: array items: $ref: '#/components/schemas/ServerPublicNetwork' @@ -1753,15 +1846,15 @@ components: example: 'Server #1 used for computing.' maxLength: 250 os: - description: The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. + description: The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. type: string example: ubuntu/bionic type: - description: Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, s4.x6.c6.large or s4.x6.m6.xlarge. + description: Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, `d3.g3.c2.medium`, `s4.x6.c6.large`, `s4.x6.m6.xlarge`, `s5.x6.c3.medium`, `s5.x6.c3.large`, `s5.x6.c8.medium`, `s5.x6.c9.medium`, `s5.x6.c8.large`, `s5.x6.c9.large`, `s5.x6.m8.xlarge`, `s5.x6.m9.xlarge`, `s4.c3.medium`, `s4.c6.medium`, `s4.c6.large`, `s4.c6.xlarge`, `s4.s2.large`, `a2.c9.large` or `a2.c9.xlarge`. type: string example: s1.c1.small location: - description: Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. + description: Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. type: string example: PHX cpu: @@ -1911,15 +2004,15 @@ components: example: 'Server #1 used for computing.' maxLength: 250 os: - description: The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. + description: The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `rockylinux/rockylinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. type: string example: ubuntu/bionic type: - description: Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`, s4.x6.c6.large or s4.x6.m6.xlarge. + description: Server type ID. Cannot be changed once a server is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `a1.c5.xlarge`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge`, `d3.g2.c3.xlarge`,`d3.g3.c2.medium`, `s4.x6.c6.large`, `s4.x6.m6.xlarge`, `s5.x6.c3.medium`, `s5.x6.c3.large`, `s5.x6.c8.medium`, `s5.x6.c9.medium`, `s5.x6.c8.large`, `s5.x6.c9.large`, `s5.x6.m8.xlarge`, `s5.x6.m9.xlarge`, `s4.c3.medium`, `s4.c6.medium`, `s4.c6.large`, `s4.c6.xlarge`, `s4.s2.large`, `a2.c9.large` or `a2.c9.xlarge`. type: string example: s1.c1.small location: - description: Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. + description: Server location ID. Cannot be changed once a server is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. type: string example: PHX installDefaultSshKeys: @@ -2015,7 +2108,7 @@ components: description: Update network details of bare metal server. properties: ips: - description: List of IPs to be associated to the server.
Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). IPs must be within the network's range.
Setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
  • Assign IP addresses which are considered as reserved in network.
+ description: List of IPs to be associated to the server.
Valid IP formats include single IP addresses or IP ranges (IPv4 or IPv6). All IPs must be within the network's range.
Setting the `force` query parameter to `true` allows you to:
  • Assign no specific IP addresses by designating an empty array of IPs.
  • Assign one or more IP addresses which are already configured on other resource(s) in network.
  • Assign IP addresses which are considered as reserved in network.
type: array items: type: string @@ -2049,7 +2142,7 @@ components: example: 'Server #1 used for computing.' maxLength: 250 os: - description: The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux8`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `proxmox/bullseye`, `proxmox/proxmox8`, `netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. + description: The server’s OS ID used when the server was created. Currently this field should be set to either `ubuntu/bionic`, `ubuntu/focal`, `ubuntu/jammy`, `ubuntu/jammy+pytorch`, `ubuntu/noble`, `centos/centos7`, `centos/centos8`, `windows/srv2019std`, `windows/srv2019dc`, `windows/srv2022std`, `windows/srv2022dc`, `windows/srv2025std`, `windows/srv2025dc`, `esxi/esxi70`, `esxi/esxi80`, `almalinux/almalinux8`, `almalinux/almalinux9`, `rockylinux/rockylinux8`, `rockylinux/rockylinux9`, `virtuozzo/virtuozzo7`, `oraclelinux/oraclelinux9`, `debian/bullseye`, `debian/bookworm`, `debian/trixie`, `proxmox/bullseye`, `proxmox/proxmox8`, `proxmox/proxmox9`,`netris/controller`, `netris/softgate_1g`, `netris/softgate_10g` or `netris/softgate_25g`. type: string example: ubuntu/bionic installDefaultSshKeys: @@ -2120,6 +2213,14 @@ components: - 172.217.22.14 - 10.111.14.40/29 - 10.111.14.66 - 10.111.14.71 + bringYourOwnLicense: + description: | + Use a Bring Your Own (BYO) Windows license. + If true, the server is provisioned in trial mode, and you must activate your own license. + If false (default), the server includes a managed Windows license billed by the platform. + type: boolean + example: false + default: false esxi: description: VMWare ESXi configuration properties. type: object @@ -2225,6 +2326,16 @@ components: description: Server pricing model. Currently this field should be set to `ONE_MONTH_RESERVATION`, `TWELVE_MONTHS_RESERVATION`, `TWENTY_FOUR_MONTHS_RESERVATION` or `THIRTY_SIX_MONTHS_RESERVATION`. type: string example: ONE_MONTH_RESERVATION + ReservationTransferDetails: + type: object + description: Reservation transfer details. + required: + - targetServerId + properties: + targetServerId: + description: ID of target server to transfer reservation to. + type: string + example: 54a21648dasda4s9843a17 SshKey: type: object description: SSH Key. diff --git a/specs/pnap_ip_api.spec.yaml b/specs/pnap_ip_api.spec.yaml index 0f400a4c..bc0131ea 100644 --- a/specs/pnap_ip_api.spec.yaml +++ b/specs/pnap_ip_api.spec.yaml @@ -113,6 +113,7 @@ paths: status: unassigned description: 'IP Block #1 used for publicly accessing server #1.' isBringYourOwn: false + isSystemManaged: false createdOn: '2021-03-13T20:24:32.491Z' '400': $ref: '#/components/responses/BadRequest' @@ -277,7 +278,7 @@ components: - cidrBlockSize properties: location: - description: IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. + description: IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. type: string example: PHX cidrBlockSize: @@ -313,7 +314,7 @@ components: type: string example: 6047127fed34ecc3ba8402d2 location: - description: IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. + description: IP Block location ID. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. type: string example: PHX cidrBlockSize: @@ -329,9 +330,13 @@ components: type: string example: V4 status: - description: 'The status of the IP Block. Can have one of the following values: `creating` , `assigning` , `error assigning` , `assigned` , `unassigning` , `error unassigning` or `unassigned`.' + description: 'The status of the IP Block. Can have one of the following values: `creating`, `subnetted`, `assigning` , `error assigning` , `assigned` , `unassigning` , `error unassigning` or `unassigned`.' type: string example: unassigned + parentIpBlockAllocationId: + description: IP Block parent identifier. If present, this block is subnetted from the parent IP Block. + type: string + example: 5edf1c9b4212930ac543d999 assignedResourceId: description: ID of the resource assigned to the IP Block. type: string @@ -355,6 +360,10 @@ components: value: beta - name: group value: discounted + isSystemManaged: + description: True if the IP block is a `system managed` block. + type: boolean + example: false isBringYourOwn: description: True if the IP block is a `bring your own` block. type: boolean diff --git a/specs/pnap_location_api.spec.yaml b/specs/pnap_location_api.spec.yaml index e9fbd1d5..8bc8b742 100644 --- a/specs/pnap_location_api.spec.yaml +++ b/specs/pnap_location_api.spec.yaml @@ -29,7 +29,7 @@ paths: description: Location of interest in: query schema: - $ref: '#/components/schemas/LocationEnum' + $ref: '#/components/schemas/ProductLocationEnum' example: ASH - name: productCategory required: false @@ -71,7 +71,7 @@ components: productCategoryDescription: Network storage properties: location: - $ref: '#/components/schemas/LocationEnum' + $ref: '#/components/schemas/ProductLocationEnum' locationDescription: type: string example: Phoenix, USA @@ -96,8 +96,14 @@ components: example: Bare metal server required: - productCategory - LocationEnum: - description: The location code. + ProductLocationEnum: + description: | + This enum is used only in product-related schemas and contains + only currently active and supported locations. + Deprecated or retired locations are intentionally excluded and will not appear + in create/update operations. + Historical data in other API responses may still reference deprecated locations, + but those values are not part of this enum. type: string enum: - PHX @@ -106,7 +112,6 @@ components: - SGP - CHI - SEA - - AUS ProductCategoryEnum: description: The product category. type: string diff --git a/specs/pnap_network_api.spec.yaml b/specs/pnap_network_api.spec.yaml index 2407ea40..7ecc1d1d 100644 --- a/specs/pnap_network_api.spec.yaml +++ b/specs/pnap_network_api.spec.yaml @@ -53,7 +53,7 @@ paths: required: false description: If present will filter the result by the given location of the Private Networks. schema: - description: Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. + description: Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. type: string example: PHX responses: @@ -388,7 +388,7 @@ paths: required: false description: If present will filter the result by the given location of the Public Networks. schema: - description: Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. + description: Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. type: string example: PHX responses: @@ -943,7 +943,7 @@ paths: required: false description: If present will filter the result by the given location of the BGP Peer Group. schema: - description: Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. + description: Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. type: string example: PHX responses: @@ -959,6 +959,15 @@ paths: - id: 60473c2509268bc77fd06d29 status: READY location: ASH + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d2 + cidr: 10.111.14.40/29 + ipVersion: V4 + status: READY + - ipAllocationId: 6047127fed34ecc3ba8402e2 + cidr: 2607:ff00:313:80c0::/58 + ipVersion: V6 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d2 cidr: 10.111.14.40/29 @@ -980,6 +989,9 @@ paths: peeringLoopbacksV4: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 createdOn: '2024-03-01T10:30:00Z' @@ -987,6 +999,11 @@ paths: - id: 60473c2509268bc77fd06d30 status: READY location: PHX + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d3 + cidr: 10.121.14.40/29 + ipVersion: V4 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d3 cidr: 10.121.14.40/29 @@ -1008,6 +1025,9 @@ paths: peeringLoopbacksV4: - 170.254.247.0 - 170.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 createdOn: '2024-03-01T10:30:00Z' @@ -1060,6 +1080,15 @@ paths: id: 60473c2509268bc77fd06d29 status: PENDING location: PHX + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d2 + cidr: 10.111.14.40/29 + ipVersion: V4 + status: READY + - ipAllocationId: 6047127fed34ecc3ba8402e2 + cidr: 2607:ff00:313:80c0::/58 + ipVersion: V6 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d2 cidr: 10.111.14.40/29 @@ -1077,6 +1106,9 @@ paths: peeringLoopbacksV4: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 lastUpdatedOn: '2024-03-01T14:30:00Z' @@ -1085,6 +1117,15 @@ paths: id: 60473c2509268bc77fd06d29 status: PENDING location: ASH + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d2 + cidr: 10.111.14.40/29 + ipVersion: V4 + status: READY + - ipAllocationId: 6047127fed34ecc3ba8402e2 + cidr: 2607:ff00:313:80c0::/58 + ipVersion: V6 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d2 cidr: 10.111.14.40/29 @@ -1102,6 +1143,9 @@ paths: peeringLoopbacksV4: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 lastUpdatedOn: '2024-03-01T14:30:00Z' @@ -1146,6 +1190,15 @@ paths: id: 60473c2509268bc77fd06d29 status: READY location: ASH + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d2 + cidr: 10.111.14.40/29 + ipVersion: V4 + status: READY + - ipAllocationId: 6047127fed34ecc3ba8402e2 + cidr: 2607:ff00:313:80c0::/58 + ipVersion: V6 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d2 cidr: 10.111.14.40/29 @@ -1167,6 +1220,9 @@ paths: peeringLoopbacksV4: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 createdOn: '2024-03-01T10:30:00Z' @@ -1217,6 +1273,15 @@ paths: id: 60473c2509268bc77fd06d29 status: PENDING location: ASH + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d2 + cidr: 10.111.14.40/29 + ipVersion: V4 + status: READY + - ipAllocationId: 6047127fed34ecc3ba8402e2 + cidr: 2607:ff00:313:80c0::/58 + ipVersion: V6 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d2 cidr: 10.111.14.40/29 @@ -1238,6 +1303,9 @@ paths: peeringLoopbacksV4: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 createdOn: '2024-03-01T10:30:00Z' @@ -1247,6 +1315,15 @@ paths: id: 60473c2509268bc77fd06d29 status: PENDING location: ASH + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d2 + cidr: 10.111.14.40/29 + ipVersion: V4 + status: READY + - ipAllocationId: 6047127fed34ecc3ba8402e2 + cidr: 2607:ff00:313:80c0::/58 + ipVersion: V6 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d2 cidr: 10.111.14.40/29 @@ -1268,6 +1345,9 @@ paths: peeringLoopbacksV4: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 createdOn: '2024-03-01T10:30:00Z' @@ -1304,6 +1384,15 @@ paths: id: 60473c2509268bc77fd06d29 status: PENDING location: ASH + ipPrefixes: + - ipAllocationId: 6047127fed34ecc3ba8402d2 + cidr: 10.111.14.40/29 + ipVersion: V4 + status: READY + - ipAllocationId: 6047127fed34ecc3ba8402e2 + cidr: 2607:ff00:313:80c0::/58 + ipVersion: V6 + status: READY ipv4Prefixes: - ipv4AllocationId: 6047127fed34ecc3ba8402d2 cidr: 10.111.14.40/29 @@ -1325,10 +1414,15 @@ paths: peeringLoopbacksV4: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: 10 holdTimerSeconds: 30 createdOn: '2024-03-01T10:30:00Z' lastUpdatedOn: '2024-03-01T14:30:00Z' + '204': + description: The BGP Peer Group has been deleted. '400': $ref: '#/components/responses/BadRequest' '401': @@ -1383,7 +1477,7 @@ components: type: string example: 603f3e995c18d515cda9c4f8 resourceType: - description: The resource's type. + description: 'The resource''s type. Can have one of the following values: `server`, `storage` or `virtual`.' type: string example: server ips: @@ -1500,7 +1594,7 @@ components: maxLength: 250 example: Further details on the network location: - description: The location of this private network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. + description: The location of this private network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. type: string example: PHX locationDefault: @@ -1594,7 +1688,7 @@ components: maxLength: 100 example: Sample Network location: - description: The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. + description: The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. type: string example: PHX description: @@ -1650,7 +1744,7 @@ components: maxLength: 250 example: Further details on the network. location: - description: The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`. + description: The location of this public network. Supported values are `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`. type: string example: PHX vlanId: @@ -1691,7 +1785,8 @@ components: example: true BgpIPv4Prefix: type: object - description: The BGP IPv4 Prefix. + description: The BGP IPv4 Prefix. Deprecated in favour of generic BgpIpPrefix. + deprecated: true required: - ipv4AllocationId - cidr @@ -1720,6 +1815,31 @@ components: description: The Boolean value of the BGP IPv4 Prefix is in use. type: boolean example: false + BgpIpPrefix: + type: object + description: The BGP IP Prefix. + required: + - ipAllocationId + - cidr + - ipVersion + - status + properties: + ipAllocationId: + description: IP allocation ID. + type: string + example: 6047127fed34ecc3ba8402d2 + cidr: + description: The IP block in CIDR format, dependent on IP version. + type: string + example: 10.111.14.40/29 + ipVersion: + description: The IP block version. + type: string + example: V4 + status: + description: 'The BGP IP Prefix status. Can have one of the following values: `PENDING`, `BUSY`, `READY`, `ERROR` and `DELETING`.' + type: string + example: READY AsnDetails: type: object description: BGP Peer Group ASN details. @@ -1754,6 +1874,7 @@ components: - id - status - location + - ipPrefixes - ipv4Prefixes - targetAsnDetails - password @@ -1761,6 +1882,7 @@ components: - rpkiRoaOriginAsn - eBgpMultiHop - peeringLoopbacksV4 + - peeringLoopbacksV6 - keepAliveTimerSeconds - holdTimerSeconds properties: @@ -1773,14 +1895,20 @@ components: type: string example: READY location: - description: 'The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`.' + description: 'The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`.' type: string example: ASH ipv4Prefixes: - description: The List of the BGP Peer Group IPv4 prefixes. + description: The List of the BGP Peer Group IPv4 prefixes. Deprecated in favour of generic ipPrefixes. + deprecated: true type: array items: $ref: '#/components/schemas/BgpIPv4Prefix' + ipPrefixes: + description: The List of the BGP Peer Group IP prefixes. + type: array + items: + $ref: '#/components/schemas/BgpIpPrefix' targetAsnDetails: $ref: '#/components/schemas/AsnDetails' activeAsnDetails: @@ -1815,6 +1943,15 @@ components: example: - 169.254.247.0 - 169.254.247.1 + peeringLoopbacksV6: + description: The IPv6 Peering Loopback addresses of the BGP Peer Group. Valid IP formats are IPv6 addresses. + type: array + items: + type: string + example: fd00:0:0:1005::2 + example: + - fd00:0:0:1005::1 + - fd00:0:0:1005::2 keepAliveTimerSeconds: description: The Keep Alive Timer in seconds of the BGP Peer Group. type: integer @@ -1842,7 +1979,7 @@ components: - advertisedRoutes properties: location: - description: 'The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` and `AUS`.' + description: 'The BGP Peer Group location. Can have one of the following values: `PHX`, `ASH`, `SGP`, `NLD`, `CHI` and `SEA`.' type: string example: ASH asn: diff --git a/specs/pnap_rancher_solution_api.spec.yaml b/specs/pnap_rancher_solution_api.spec.yaml index 5feb2df3..52d3e443 100644 --- a/specs/pnap_rancher_solution_api.spec.yaml +++ b/specs/pnap_rancher_solution_api.spec.yaml @@ -35,7 +35,7 @@ paths: tags: - Clusters description: | - Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. + Create a Rancher Server Deployment as described in Rancher Docs Architecture. Rancher Server allows the creation, import and management of multiple Downstream User Kubernetes Clusters. This is not a Downstream User Cluster. Knowledge base article to help you can be found here. summary: Create a Rancher Server Deployment. security: @@ -257,7 +257,7 @@ components: type: string example: My first Rancher Server Cluster. location: - description: Deployment location. Cannot be changed once a cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. + description: Deployment location. Cannot be changed once a cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. type: string example: PHX initialClusterVersion: @@ -381,12 +381,12 @@ components: default: 1 example: 3 serverType: - description: Node server type. Cannot be changed once the cluster is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c1.small`, `d1.c2.small`, `d1.c3.small`, `d1.c4.small`, `d1.c1.medium`, `d1.c2.medium`, `d1.c3.medium`, `d1.c4.medium`, `d1.c1.large`, `d1.c2.large`, `d1.c3.large`, `d1.c4.large`, `d1.m1.medium`, `d1.m2.medium`, `d1.m3.medium`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge` or `d3.g2.c3.xlarge`. + description: Node server type. Cannot be changed once the cluster is created. Currently this field should be set to either `s0.d1.small`, `s0.d1.medium`, `s1.c1.small`, `s1.c1.medium`, `s1.c2.medium`, `s1.c2.large`, `s1.e1.small`, `s1.e1.medium`, `s1.e1.large`, `s2.c1.small`, `s2.c1.medium`, `s2.c1.large`, `s2.c2.small`, `s2.c2.medium`, `s2.c2.large`, `d1.c4.small`, `d1.c4.medium`, `d1.c4.large`, `d1.m4.medium`, `d2.c1.medium`, `d2.c2.medium`, `d2.c3.medium`, `d2.c4.medium`, `d2.c5.medium`, `d2.c1.large`, `d2.c2.large`, `d2.c3.large`, `d2.c4.large`, `d2.c5.large`, `d2.m1.xlarge`, `d2.m2.xxlarge`, `d2.m3.xlarge`, `d2.m4.xlarge`, `d2.m5.xlarge`, `d2.c4.db1.pliops1`, `d3.m4.xlarge`, `d3.m5.xlarge`, `d3.m6.xlarge`, `a1.c5.large`, `d3.s5.xlarge`, `d3.m4.xxlarge`, `d3.m5.xxlarge`, `d3.m6.xxlarge`, `s3.c3.medium`, `s3.c3.large`, `d3.c4.medium`, `d3.c5.medium`, `d3.c6.medium`, `d3.c1.large`, `d3.c2.large`, `d3.c3.large`, `d3.m1.xlarge`, `d3.m2.xlarge`, `d3.m3.xlarge`, `d3.g2.c1.xlarge`, `d3.g2.c2.xlarge` or `d3.g2.c3.xlarge`. type: string default: s0.d1.small example: s0.d1.small location: - description: Workload cluster location. Cannot be changed once cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI`, `SEA` or `AUS`. + description: Workload cluster location. Cannot be changed once cluster is created. Currently this field should be set to `PHX`, `ASH`, `SGP`, `NLD`, `CHI` or `SEA`. type: string example: PHX SshConfig: diff --git a/template/README.mustache b/template/README.mustache index 746eb0de..79054465 100644 --- a/template/README.mustache +++ b/template/README.mustache @@ -47,4 +47,12 @@ Then import the package: import {{{packageName}}} ``` +### Tests + +Execute `pytest` to run the tests. + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + {{> common_README }} diff --git a/template/api_client.mustache b/template/api_client.mustache index 7149cfc4..07099f90 100644 --- a/template/api_client.mustache +++ b/template/api_client.mustache @@ -1,24 +1,26 @@ -# coding: utf-8 - {{>partial_header}} -import atexit + import datetime from dateutil.parser import parse +from enum import Enum +import decimal import json import mimetypes import os import re import tempfile +import uuid from urllib.parse import quote -from typing import Tuple, Optional, List +from typing import Tuple, Optional, List, Dict, Union +from pydantic import SecretStr {{#tornado}} import tornado.gen {{/tornado}} from {{packageName}}.configuration import Configuration -from {{packageName}}.api_response import ApiResponse +from {{packageName}}.api_response import ApiResponse, T as ApiResponseT import {{modelPackage}} from {{packageName}} import rest from {{packageName}}.exceptions import ( @@ -31,6 +33,7 @@ from {{packageName}}.exceptions import ( ServiceException ) +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] class ApiClient: """Generic API client for OpenAPI client library builds. @@ -57,6 +60,7 @@ class ApiClient: 'bool': bool, 'date': datetime.date, 'datetime': datetime.datetime, + 'decimal': decimal.Decimal, 'object': object, } _pool = None @@ -85,7 +89,7 @@ class ApiClient: # Set default X-Powered-By. self.powered_by = f"PNAP-python-sdk-bmc/{{{packageName}}}/{{{packageVersion}}}" -{{#asyncio}} +{{#async}} async def __aenter__(self): return self @@ -94,31 +98,14 @@ class ApiClient: async def close(self): await self.rest_client.close() -{{/asyncio}} -{{^asyncio}} +{{/async}} +{{^async}} def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): pass -{{/asyncio}} - - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, 'unregister'): - atexit.unregister(self.close) - - @property - def powered_by(self): - """Powered By for this API client""" - return self.default_headers['X-Powered-By'] - - @powered_by.setter - def powered_by(self, value): - self.default_headers['X-Powered-By'] = value +{{/async}} @property def user_agent(self): @@ -172,7 +159,7 @@ class ApiClient: collection_formats=None, _host=None, _request_auth=None - ) -> Tuple: + ) -> RequestSerialized: """Builds the HTTP request params needed by the request. :param method: Method to call. @@ -231,7 +218,8 @@ class ApiClient: post_params, collection_formats ) - post_params.extend(self.files_parameters(files)) + if files: + post_params.extend(self.files_parameters(files)) # auth setting self.update_params_for_auth( @@ -249,7 +237,7 @@ class ApiClient: body = self.sanitize_for_serialization(body) # request url - if _host is None: + if _host is None or self.configuration.ignore_operation_servers: url = self.configuration.host + resource_path else: # use server/host defined in path or operation instead @@ -270,7 +258,7 @@ class ApiClient: {{#tornado}} @tornado.gen.coroutine {{/tornado}} - {{#asyncio}}async {{/asyncio}}def call_api( + {{#async}}async {{/async}}def call_api( self, method, url, @@ -293,7 +281,7 @@ class ApiClient: try: # perform request and return response - response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.rest_client.request( + response_data = {{#async}}await {{/async}}{{#tornado}}yield {{/tornado}}self.rest_client.request( method, url, headers=header_params, body=body, post_params=post_params, @@ -301,23 +289,23 @@ class ApiClient: ) except ApiException as e: - if e.body: - e.body = e.body.decode('utf-8') raise e return response_data def response_deserialize( self, - response_data: rest.RESTResponse = None, - response_types_map=None - ) -> ApiResponse: + response_data: rest.RESTResponse, + response_types_map: Optional[Dict[str, ApiResponseT]]=None + ) -> ApiResponse[ApiResponseT]: """Deserializes response into an object. :param response_data: RESTResponse object to be deserialized. :param response_types_map: dict of response types. :return: ApiResponse """ + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + assert response_data.data is not None, msg response_type = response_types_map.get(str(response_data.status), None) if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: @@ -334,12 +322,12 @@ class ApiClient: 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" response_text = response_data.data.decode(encoding) - return_data = self.deserialize(response_text, response_type) + return_data = self.deserialize(response_text, response_type, content_type) finally: if not 200 <= response_data.status <= 299: raise ApiException.from_response( @@ -351,7 +339,7 @@ class ApiClient: return ApiResponse( status_code = response_data.status, data = return_data, - headers = response_data.getheaders(), + headers = response_data.headers, raw_data = response_data.data ) @@ -359,9 +347,11 @@ class ApiClient: """Builds a JSON POST object. If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() 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. @@ -371,8 +361,14 @@ class ApiClient: """ if obj is None: return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + 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 @@ -383,6 +379,8 @@ class ApiClient: ) 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 @@ -392,28 +390,49 @@ class ApiClient: # and attributes which value is not None. # Convert attribute name to json key in # model definition for request. - obj_dict = obj.to_dict() + if hasattr(obj, 'to_dict') and callable(getattr(obj, 'to_dict')): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + if isinstance(obj_dict, list): + # here we handle instances that can either be a list or something else, and only became a real list by calling to_dict() + return self.sanitize_for_serialization(obj_dict) return { key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() } - def deserialize(self, response_text, response_type): + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): """Deserializes response into an object. :param response: RESTResponse object to be deserialized. :param response_type: class literal for deserialized object, or string of class name. + :param content_type: content type of response. :return: deserialized object. """ # fetch data from response object - try: - data = json.loads(response_text) - except ValueError: + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif re.match(r'^application/(json|[\w!#$&.+\-^_]+\+json)\s*(;|$)', content_type, re.IGNORECASE): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif re.match(r'^text\/[a-z.+-]+\s*(;|$)', content_type, re.IGNORECASE): data = response_text + else: + raise ApiException( + status=0, + reason="Unsupported content type: {0}".format(content_type) + ) return self.__deserialize(data, response_type) @@ -430,12 +449,16 @@ class ApiClient: if isinstance(klass, str): if klass.startswith('List['): - sub_kls = re.match(r'List\[(.*)]', klass).group(1) + m = re.match(r'List\[(.*)]', klass) + assert m is not None, "Malformed List type definition" + sub_kls = m.group(1) return [self.__deserialize(sub_data, sub_kls) for sub_data in data] if klass.startswith('Dict['): - sub_kls = re.match(r'Dict\[([^,]*), (.*)]', klass).group(2) + m = re.match(r'Dict\[([^,]*), (.*)]', klass) + assert m is not None, "Malformed Dict type definition" + sub_kls = m.group(2) return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} @@ -447,12 +470,16 @@ class ApiClient: 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: return self.__deserialize_model(data, klass) @@ -463,7 +490,7 @@ class ApiClient: :param dict collection_formats: Parameter collection formats :return: Parameters as list of tuples, collections formatted """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -493,7 +520,7 @@ class ApiClient: :param dict collection_formats: Parameter collection formats :return: URL query string (e.g. a=Hello%20World&b=123) """ - new_params = [] + new_params: List[Tuple[str, str]] = [] if collection_formats is None: collection_formats = {} for k, v in params.items() if isinstance(params, dict) else params: @@ -507,7 +534,7 @@ class ApiClient: if k in collection_formats: collection_format = collection_formats[k] if collection_format == 'multi': - new_params.extend((k, value) for value in v) + new_params.extend((k, quote(str(value))) for value in v) else: if collection_format == 'ssv': delimiter = ' ' @@ -523,33 +550,41 @@ class ApiClient: else: new_params.append((k, quote(str(v)))) - return "&".join(["=".join(item) for item in new_params]) + return "&".join(["=".join(map(str, item)) for item in new_params]) - def files_parameters(self, files=None): + def files_parameters( + self, + files: Dict[str, Union[str, bytes, List[str], List[bytes], Tuple[str, bytes]]], + ): """Builds form parameters. :param files: File parameters. :return: Form parameters with files. """ params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or 'application/octet-stream' - ) - params.append( - tuple([k, tuple([filename, filedata, mimetype])]) - ) - + for k, v in files.items(): + if isinstance(v, str): + with open(v, 'rb') as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + elif isinstance(v, tuple): + filename, filedata = v + elif isinstance(v, list): + for file_param in v: + params.extend(self.files_parameters({k: file_param})) + continue + else: + raise ValueError("Unsupported file value") + mimetype = ( + mimetypes.guess_type(filename)[0] + or 'application/octet-stream' + ) + params.append( + tuple([k, tuple([filename, filedata, mimetype])]) + ) return params def select_header_accept(self, accepts: List[str]) -> Optional[str]: @@ -685,12 +720,16 @@ class ApiClient: os.close(fd) os.remove(path) - content_disposition = response.getheader("Content-Disposition") + content_disposition = response.headers.get("Content-Disposition") if content_disposition: - filename = re.search( + m = re.search( r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) + ) + assert m is not None, "Unexpected 'content-disposition' header value" + 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: @@ -757,6 +796,24 @@ class ApiClient: ) ) + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException( + status=0, + reason=( + "Failed to parse `{0}` as `{1}`" + .format(data, klass) + ) + ) + def __deserialize_model(self, data, klass): """Deserializes list or dict to model. diff --git a/template/common_README.mustache b/template/common_README.mustache index dc4f9b07..9dae08c9 100644 --- a/template/common_README.mustache +++ b/template/common_README.mustache @@ -1,14 +1,14 @@ ```python {{#apiInfo}}{{#apis}}{{#-last}}{{#hasHttpSignatureMethods}}import datetime{{/hasHttpSignatureMethods}}{{/-last}}{{/apis}}{{/apiInfo}} -import time import {{{packageName}}} from {{{packageName}}}.rest import ApiException from pprint import pprint {{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#-first}} {{> python_doc_auth_partial}} + # Enter a context with an instance of the API client -{{#asyncio}}async {{/asyncio}}with {{{packageName}}}.ApiClient(configuration) as api_client: +{{#async}}async {{/async}}with {{{packageName}}}.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = {{{packageName}}}.{{{classname}}}(api_client) {{#allParams}} @@ -19,7 +19,7 @@ from pprint import pprint {{#summary}} # {{{.}}} {{/summary}} - {{#returnType}}api_response = {{/returnType}}{{#asyncio}}await {{/asyncio}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) + {{#returnType}}api_response = {{/returnType}}{{#async}}await {{/async}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) {{#returnType}} print("The response of {{classname}}->{{operationId}}:\n") pprint(api_response) @@ -45,6 +45,7 @@ keycloakOpenId = KeycloakOpenID(server_url=serverUrl, client_secret_key=clientSecret) ACCESS_TOKEN = keycloakOpenId.token(grant_type=grantType)['access_token'] +``` ## Documentation for API Endpoints diff --git a/template/pyproject.mustache b/template/pyproject.mustache index 4e6bf9b4..6e97cda5 100644 --- a/template/pyproject.mustache +++ b/template/pyproject.mustache @@ -1,41 +1,169 @@ +{{#poetry1}} [tool.poetry] +{{/poetry1}} +{{^poetry1}} +[project] +{{/poetry1}} name = "{{{packageName}}}" version = "{{{packageVersion}}}" description = "{{{appName}}}" +{{#poetry1}} authors = ["{{infoName}}{{^infoName}}OpenAPI Generator Community{{/infoName}} <{{infoEmail}}{{^infoEmail}}team@openapitools.org{{/infoEmail}}>"] -license = "{{{licenseInfo}}}{{^licenseInfo}}NoLicense{{/licenseInfo}}" +{{/poetry1}} +{{^poetry1}} +authors = [ + {name = "{{infoName}}{{^infoName}}OpenAPI Generator Community{{/infoName}}",email = "{{infoEmail}}{{^infoEmail}}team@openapitools.org{{/infoEmail}}"}, +] +{{/poetry1}} +{{#licenseInfo}} +{{#poetry1}} +license = "{{{licenseInfo}}}" +{{/poetry1}} +{{^poetry1}} +license = { text = "{{{licenseInfo}}}" } +{{/poetry1}} +{{/licenseInfo}} readme = "README.md" -repository = "https://github.com/phoenixnap/python-sdk-bmc" keywords = ["OpenAPI", "OpenAPI-Generator", "{{{appName}}}"] +{{#poetry1}} include = ["{{packageName}}/py.typed"] [tool.poetry.dependencies] -python = "^3.7" - -urllib3 = ">= 1.25.3" -python-dateutil = ">=2.8.2" +python = "^3.9" +{{^async}} +urllib3 = ">= 2.1.0, < 3.0.0" +{{/async}} +python-dateutil = ">= 2.8.2" {{#asyncio}} aiohttp = ">= 3.8.4" aiohttp-retry = ">= 2.8.3" {{/asyncio}} +{{#httpx}} +httpx = ">= 0.28.1" +{{/httpx}} {{#tornado}} -tornado = ">=4.2,<5" +tornado = ">=4.2, <5" {{/tornado}} {{#hasHttpSignatureMethods}} pem = ">= 19.3.0" pycryptodome = ">= 3.9.0" {{/hasHttpSignatureMethods}} -pydantic = ">=2" -typing-extensions = ">=4.7.1" +pydantic = ">= 2" +typing-extensions = ">= 4.7.1" +{{#lazyImports}} +lazy-imports = ">= 1, < 2" +{{/lazyImports}} +{{/poetry1}} +{{^poetry1}} +requires-python = ">=3.9" + +dependencies = [ +{{^async}} + "urllib3 (>=2.1.0,<3.0.0)", +{{/async}} + "python-dateutil (>=2.8.2)", +{{#httpx}} + "httpx (>=0.28.1)", +{{/httpx}} +{{#asyncio}} + "aiohttp (>=3.8.4)", + "aiohttp-retry (>=2.8.3)", +{{/asyncio}} +{{#tornado}} + "tornado (>=4.2,<5)", +{{/tornado}} +{{#hasHttpSignatureMethods}} + "pem (>=19.3.0)", + "pycryptodome (>=3.9.0)", +{{/hasHttpSignatureMethods}} + "pydantic (>=2)", + "typing-extensions (>=4.7.1)", +{{#lazyImports}} + "lazy-imports (>=1,<2)" +{{/lazyImports}} +] +[project.urls] +Repository = "https://{{{gitHost}}}/{{{gitUserId}}}/{{{gitRepoId}}}" + +{{/poetry1}} +{{^poetry1}} +[tool.poetry] +requires-poetry = ">=2.0" +{{/poetry1}} + +{{#poetry1}} [tool.poetry.dev-dependencies] -pytest = ">=7.2.1" -tox = ">=3.9.0" -flake8 = ">=4.0.0" +{{/poetry1}} +{{^poetry1}} +[tool.poetry.group.dev.dependencies] +{{/poetry1}} +pytest = ">= 7.2.1" +pytest-cov = ">= 2.8.1" +tox = ">= 3.9.0" +flake8 = ">= 4.0.0" +types-python-dateutil = ">= 2.8.19.14" +mypy = ">= 1.5" + [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" \ No newline at end of file +extension-pkg-whitelist = "pydantic" + +[tool.mypy] +files = [ + "{{{packageName}}}", + #"test", # auto-generated tests + "tests", # hand-written tests +] +# TODO: enable "strict" once all these individual checks are passing +# strict = true + +# List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true + +## Getting these passing should be easy +strict_equality = true +extra_checks = true + +## Strongly recommend enabling this one as soon as you can +check_untyped_defs = true + +## These shouldn't be too much additional work, but may be tricky to +## get passing if you use a lot of untyped libraries +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true + +### These next few are various gradations of forcing use of type annotations +#disallow_untyped_calls = true +#disallow_incomplete_defs = true +#disallow_untyped_defs = true +# +### This one isn't too hard to get passing, but return on investment is lower +#no_implicit_reexport = true +# +### This one can be tricky to get passing if you use a lot of untyped libraries +#warn_return_any = true + +[[tool.mypy.overrides]] +module = [ + "{{{packageName}}}.configuration", +] +warn_unused_ignores = true +strict_equality = true +extra_checks = true +check_untyped_defs = true +disallow_subclassing_any = true +disallow_untyped_decorators = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_incomplete_defs = true +disallow_untyped_defs = true +no_implicit_reexport = true +warn_return_any = true \ No newline at end of file diff --git a/template/setup.mustache b/template/setup.mustache index 9bce4ef9..1b8a87fc 100644 --- a/template/setup.mustache +++ b/template/setup.mustache @@ -1,5 +1,3 @@ -# coding: utf-8 - {{>partial_header}} from setuptools import setup, find_packages # noqa: H301 @@ -10,29 +8,33 @@ from setuptools import setup, find_packages # noqa: H301 # # prerequisite: setuptools # http://pypi.python.org/pypi/setuptools -{{! UPDATE: replacing name with packageName to preserve underscores }} NAME = "{{{packageName}}}" VERSION = "{{packageVersion}}" -PYTHON_REQUIRES = ">=3.7" -{{#apiInfo}} -{{#apis}} -{{#-last}} +PYTHON_REQUIRES = ">= 3.9" REQUIRES = [ - "urllib3 >= 1.25.3, < 2.1.0", - "python-dateutil", +{{^async}} + "urllib3 >= 2.1.0, < 3.0.0", +{{/async}} + "python-dateutil >= 2.8.2", {{#asyncio}} - "aiohttp >= 3.0.0", + "aiohttp >= 3.8.4", "aiohttp-retry >= 2.8.3", {{/asyncio}} +{{#httpx}} + "httpx >= 0.28.1", +{{/httpx}} {{#tornado}} - "tornado>=4.2,<5", + "tornado>=4.2, < 5", {{/tornado}} {{#hasHttpSignatureMethods}} - "pem>=19.3.0", - "pycryptodome>=3.9.0", + "pem >= 19.3.0", + "pycryptodome >= 3.9.0", {{/hasHttpSignatureMethods}} "pydantic >= 2", "typing-extensions >= 4.7.1", +{{#lazyImports}} + "lazy-imports >= 1, < 2", +{{/lazyImports}} ] setup( @@ -52,7 +54,4 @@ setup( {{appDescription}} """, # noqa: E501 package_data={"{{{packageName}}}": ["py.typed"]}, -) -{{/-last}} -{{/apis}} -{{/apiInfo}} +) \ No newline at end of file diff --git a/tests/README.md b/tests/README.md index 15ef7ee1..e8f8a959 100644 --- a/tests/README.md +++ b/tests/README.md @@ -37,4 +37,16 @@ pip install -r requirements.txt Once this is done, you can then run the respective test script: ```sh python pnap_network_api_test.py -``` \ No newline at end of file +``` + +### Using .venv +If you're using an immutable system, such as *NixOS*, then you'll likely want to use a **virtual environment**. + +This can be easily done by doing the following: +```sh +python3 -m venv .venv +source .venv/bin/activate +``` + +The first command creates the virtual environment, and the second command activates it for the current shell. Once done, you can follow the +instructions above as normal. \ No newline at end of file diff --git a/tests/payloads/bmcapi/servers/servers_action_provision.json b/tests/payloads/bmcapi/servers/servers_action_provision.json index bc0737d8..5ebe1a9b 100644 --- a/tests/payloads/bmcapi/servers/servers_action_provision.json +++ b/tests/payloads/bmcapi/servers/servers_action_provision.json @@ -42,7 +42,8 @@ "172.217.22.14", "10.111.14.40/29", "10.111.14.66 - 10.111.14.71" - ] + ], + "bringYourOwnLicense": false }, "managementAccessAllowedIps": [ "172.217.22.14", @@ -164,7 +165,8 @@ "172.217.22.14", "10.111.14.40/29", "10.111.14.66 - 10.111.14.71" - ] + ], + "bringYourOwnLicense": false }, "rootPassword": "MyP@ssw0rd_01", "managementUiUrl": "https://172.217.22.14", diff --git a/tests/payloads/bmcapi/servers/servers_action_reset.json b/tests/payloads/bmcapi/servers/servers_action_reset.json index f60e0ed4..6f45635f 100644 --- a/tests/payloads/bmcapi/servers/servers_action_reset.json +++ b/tests/payloads/bmcapi/servers/servers_action_reset.json @@ -13,7 +13,8 @@ "sshKeyIds": [ "5fa942e71c16abcfbead275f" ], "osConfiguration": { "windows": { - "rdpAllowedIps": [ "172.217.22.14" ] + "rdpAllowedIps": [ "172.217.22.14" ], + "bringYourOwnLicense": false }, "esxi": { "managementAccessAllowedIps": [ "172.217.22.14" ] @@ -33,7 +34,8 @@ "password" : "MyP@ssw0rd_01", "osConfiguration" : { "windows": { - "rdpAllowedIps": [ "172.217.22.14" ] + "rdpAllowedIps": [ "172.217.22.14" ], + "bringYourOwnLicense": false }, "esxi": { "rootPassword": "MyP@ssw0rd_01", diff --git a/tests/payloads/bmcapi/servers/servers_post.json b/tests/payloads/bmcapi/servers/servers_post.json index 0eb18002..8f429939 100644 --- a/tests/payloads/bmcapi/servers/servers_post.json +++ b/tests/payloads/bmcapi/servers/servers_post.json @@ -41,7 +41,8 @@ "172.217.22.14", "10.111.14.40/29", "10.111.14.66 - 10.111.14.71" - ] + ], + "bringYourOwnLicense": false }, "managementAccessAllowedIps": [ "172.217.22.14", @@ -152,7 +153,8 @@ "172.217.22.14", "10.111.14.40/29", "10.111.14.66 - 10.111.14.71" - ] + ], + "bringYourOwnLicense": false }, "rootPassword": "MyP@ssw0rd_01", "managementUiUrl": "https://172.217.22.14", diff --git a/tests/payloads/networkapi/bgp_peer_groups_delete_by_id.json b/tests/payloads/networkapi/bgp_peer_groups_delete_by_id.json index b748ea1c..181e9c24 100644 --- a/tests/payloads/networkapi/bgp_peer_groups_delete_by_id.json +++ b/tests/payloads/networkapi/bgp_peer_groups_delete_by_id.json @@ -23,6 +23,25 @@ "inUse": false } ], + "ipPrefixes": [ + { + "ipAllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false, + "ipVersion": "v6" + } + ], + "ipv6Prefixes": [ + { + "ipv4AllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false + } + ], "targetAsnDetails": { "asn": 9131072, "isBringYourOwn": true, @@ -42,6 +61,10 @@ "peeringLoopbacksV4": [ "test" ], + "peeringLoopbacksV6": [ + "1000::", + "1000::" + ], "keepAliveTimerSeconds": 3600, "holdTimerSeconds": 7200, "createdOn": "2022-04-07T13:20:30.491Z", diff --git a/tests/payloads/networkapi/bgp_peer_groups_get.json b/tests/payloads/networkapi/bgp_peer_groups_get.json index 590df249..85d2a518 100644 --- a/tests/payloads/networkapi/bgp_peer_groups_get.json +++ b/tests/payloads/networkapi/bgp_peer_groups_get.json @@ -27,6 +27,25 @@ "inUse": false } ], + "ipPrefixes": [ + { + "ipAllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false, + "ipVersion": "v6" + } + ], + "ipv6Prefixes": [ + { + "ipv4AllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false + } + ], "targetAsnDetails": { "asn": 9131072, "isBringYourOwn": true, @@ -46,6 +65,10 @@ "peeringLoopbacksV4": [ "test" ], + "peeringLoopbacksV6": [ + "1000::", + "1000::" + ], "keepAliveTimerSeconds": 3600, "holdTimerSeconds": 7200, "createdOn": "2022-04-07T13:20:30.491Z", diff --git a/tests/payloads/networkapi/bgp_peer_groups_get_by_id.json b/tests/payloads/networkapi/bgp_peer_groups_get_by_id.json index 5f2a27b7..1220c160 100644 --- a/tests/payloads/networkapi/bgp_peer_groups_get_by_id.json +++ b/tests/payloads/networkapi/bgp_peer_groups_get_by_id.json @@ -23,6 +23,25 @@ "inUse": false } ], + "ipPrefixes": [ + { + "ipAllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false, + "ipVersion": "v6" + } + ], + "ipv6Prefixes": [ + { + "ipv4AllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false + } + ], "targetAsnDetails": { "asn": 9131072, "isBringYourOwn": true, @@ -42,6 +61,10 @@ "peeringLoopbacksV4": [ "test" ], + "peeringLoopbacksV6": [ + "1000::", + "1000::" + ], "keepAliveTimerSeconds": 3600, "holdTimerSeconds": 7200, "createdOn": "2022-04-07T13:20:30.491Z", diff --git a/tests/payloads/networkapi/bgp_peer_groups_patch_by_id.json b/tests/payloads/networkapi/bgp_peer_groups_patch_by_id.json index eedc3ab4..c871f26c 100644 --- a/tests/payloads/networkapi/bgp_peer_groups_patch_by_id.json +++ b/tests/payloads/networkapi/bgp_peer_groups_patch_by_id.json @@ -32,6 +32,25 @@ "inUse": false } ], + "ipPrefixes": [ + { + "ipAllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false, + "ipVersion": "v6" + } + ], + "ipv6Prefixes": [ + { + "ipv4AllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false + } + ], "targetAsnDetails": { "asn": 9131072, "isBringYourOwn": true, @@ -51,6 +70,10 @@ "peeringLoopbacksV4": [ "test" ], + "peeringLoopbacksV6": [ + "1000::", + "1000::" + ], "keepAliveTimerSeconds": 3600, "holdTimerSeconds": 7200, "createdOn": "2022-04-07T13:20:30.491Z", diff --git a/tests/payloads/networkapi/bgp_peer_groups_post.json b/tests/payloads/networkapi/bgp_peer_groups_post.json index 02bc8d94..b2e16a92 100644 --- a/tests/payloads/networkapi/bgp_peer_groups_post.json +++ b/tests/payloads/networkapi/bgp_peer_groups_post.json @@ -28,6 +28,25 @@ "inUse": false } ], + "ipPrefixes": [ + { + "ipAllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false, + "ipVersion": "v6" + } + ], + "ipv6Prefixes": [ + { + "ipv4AllocationId": "6047127fed34ecc3ba8402d2", + "cidr": "10.111.14.40/29", + "status": "READY", + "isBringYourOwnIp": false, + "inUse": false + } + ], "targetAsnDetails": { "asn": 9131072, "isBringYourOwn": true, @@ -47,6 +66,10 @@ "peeringLoopbacksV4": [ "test" ], + "peeringLoopbacksV6": [ + "1000::", + "1000::" + ], "keepAliveTimerSeconds": 3600, "holdTimerSeconds": 7200, "createdOn": "2022-04-07T13:20:30.491Z", diff --git a/tests/pnap_audit_api_test.py b/tests/pnap_audit_api_test.py index 843e3b47..5e9604bc 100644 --- a/tests/pnap_audit_api_test.py +++ b/tests/pnap_audit_api_test.py @@ -44,7 +44,6 @@ def test_get_events_all_query_params(self): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() if __name__ == '__main__': TestUtils.reset_mockserver() diff --git a/tests/pnap_bmc_api_test.py b/tests/pnap_bmc_api_test.py index f956b359..b1d3a6db 100644 --- a/tests/pnap_bmc_api_test.py +++ b/tests/pnap_bmc_api_test.py @@ -533,7 +533,6 @@ def test_server_put_tags_by_id(self): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() if __name__ == '__main__': TestUtils.reset_mockserver() diff --git a/tests/pnap_invoicing_api_test.py b/tests/pnap_invoicing_api_test.py index 7b592675..8843befe 100644 --- a/tests/pnap_invoicing_api_test.py +++ b/tests/pnap_invoicing_api_test.py @@ -21,7 +21,6 @@ def verify_called_once(self, expectation_id): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() def test_get_invoices(self): # Setting up expectation diff --git a/tests/pnap_ip_api_test.py b/tests/pnap_ip_api_test.py index 73a81b31..86a1fcca 100644 --- a/tests/pnap_ip_api_test.py +++ b/tests/pnap_ip_api_test.py @@ -127,7 +127,6 @@ def test_ip_block_put_tags_by_id(self): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() if __name__ == '__main__': TestUtils.reset_mockserver() diff --git a/tests/pnap_location_api_test.py b/tests/pnap_location_api_test.py index d4485f72..b543aee1 100644 --- a/tests/pnap_location_api_test.py +++ b/tests/pnap_location_api_test.py @@ -3,7 +3,7 @@ from dateutil.parser import parse import pnap_location_api from pnap_location_api.api import locations_api -from pnap_location_api.models.location_enum import LocationEnum +from pnap_location_api.models.product_location_enum import ProductLocationEnum from pnap_location_api.models.product_category_enum import ProductCategoryEnum from test_utils import TestUtils @@ -30,7 +30,7 @@ def test_get_locations(self): opts = TestUtils.generate_query_params(request) # Changing values to be enums - opts['location'] = LocationEnum(opts['location']) + opts['location'] = ProductLocationEnum(opts['location']) opts['product_category'] = ProductCategoryEnum(opts['productCategory']) del opts['productCategory'] @@ -42,7 +42,6 @@ def test_get_locations(self): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() if __name__ == '__main__': TestUtils.reset_mockserver() diff --git a/tests/pnap_network_api_test.py b/tests/pnap_network_api_test.py index 0e1094e7..627bc8e1 100644 --- a/tests/pnap_network_api_test.py +++ b/tests/pnap_network_api_test.py @@ -285,7 +285,6 @@ def test_delete_bgp_peer_group_by_id(self): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() if __name__ == '__main__': TestUtils.reset_mockserver() diff --git a/tests/pnap_network_storage_api_test.py b/tests/pnap_network_storage_api_test.py index 66e723b5..3a9d0a04 100644 --- a/tests/pnap_network_storage_api_test.py +++ b/tests/pnap_network_storage_api_test.py @@ -26,7 +26,6 @@ def verify_called_once(self, expectation_id): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() def test_get_network_storages(self): # Setting up expectation diff --git a/tests/pnap_payments_api_test.py b/tests/pnap_payments_api_test.py index e78391c3..1714d883 100644 --- a/tests/pnap_payments_api_test.py +++ b/tests/pnap_payments_api_test.py @@ -20,7 +20,6 @@ def verify_called_once(self, expectation_id): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() def test_get_transactions(self): # Setting up expectation diff --git a/tests/pnap_rancher_solution_api_test.py b/tests/pnap_rancher_solution_api_test.py index 1e7536dc..b626d7ac 100644 --- a/tests/pnap_rancher_solution_api_test.py +++ b/tests/pnap_rancher_solution_api_test.py @@ -91,7 +91,6 @@ def test_delete_cluster_by_id(self): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() if __name__ == '__main__': TestUtils.reset_mockserver() diff --git a/tests/pnap_tag_api_test.py b/tests/pnap_tag_api_test.py index ef0b70c7..17b6904c 100644 --- a/tests/pnap_tag_api_test.py +++ b/tests/pnap_tag_api_test.py @@ -94,7 +94,6 @@ def test_delete_tag_by_id(self): def tearDown(self): TestUtils.reset_expectations() - self.api_client.close() if __name__ == '__main__': TestUtils.reset_mockserver()