diff --git a/README.md b/README.md index f36e116..26e768b 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ IBM Cloud services: Service Name | Module Name | Service Class Name --- | --- | --- +[Account Management](https://test.cloud.ibm.com/apidocs/account-management) | account_management_v4 | AccountManagementV4 [Case Management](https://cloud.ibm.com/apidocs/case-management?code=python) | case_management_v1 | CaseManagementV1 [Catalog Management](https://cloud.ibm.com/apidocs/resource-catalog/private-catalog?code=python) | catalog_management_v1 | CatalogManagementV1 [Context Based Restrictions](https://cloud.ibm.com/apidocs/context-based-restrictions?code=python) | context_based_restrictions_v1 | ContextBasedRestrictionsV1 diff --git a/examples/test_account_management_v4_examples.py b/examples/test_account_management_v4_examples.py new file mode 100644 index 0000000..747eb69 --- /dev/null +++ b/examples/test_account_management_v4_examples.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# (C) Copyright IBM Corp. 2026. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Examples for AccountManagementV4 +""" + +from ibm_cloud_sdk_core import ApiException, read_external_sources +import os +import pytest +from ibm_platform_services.account_management_v4 import * + +# +# This file provides an example of how to use the account_management service. +# +# The following configuration properties are assumed to be defined: +# ACCOUNT_MANAGEMENT_URL= +# ACCOUNT_MANAGEMENT_AUTH_TYPE=iam +# ACCOUNT_MANAGEMENT_APIKEY= +# ACCOUNT_MANAGEMENT_AUTH_URL= +# ACCOUNT_MANAGEMENT_ACCOUNT_ID= +# +# These configuration properties can be exported as environment variables, or stored +# in a configuration file and then: +# export IBM_CREDENTIALS_FILE= +# +config_file = 'account_management_v4.env' + +account_management_service = None + +config = None + +account_id = None + + +############################################################################## +# Start of Examples for Service: AccountManagementV4 +############################################################################## +# region +class TestAccountManagementV4Examples: + """ + Example Test Class for AccountManagementV4 + """ + + @classmethod + def setup_class(cls): + global account_management_service + if os.path.exists(config_file): + os.environ['IBM_CREDENTIALS_FILE'] = config_file + + # begin-common + + account_management_service = AccountManagementV4.new_instance() + + # end-common + assert account_management_service is not None + + # Load the configuration + global config + config = read_external_sources(AccountManagementV4.DEFAULT_SERVICE_NAME) + global account_id + account_id = config['ACCOUNT_ID'] + print('Setup complete.') + + needscredentials = pytest.mark.skipif( + not os.path.exists(config_file), reason="External configuration not available, skipping..." + ) + + @needscredentials + def test_get_account_example(self): + """ + get_account request example + """ + try: + print('\nget_account() result:') + + # begin-getAccount + + response = account_management_service.get_account( + account_id=account_id, + ) + account_response = response.get_result() + + print(json.dumps(account_response, indent=2)) + + # end-getAccount + + except ApiException as e: + pytest.fail(str(e)) + + +# endregion +############################################################################## +# End of Examples for Service: AccountManagementV4 +############################################################################## diff --git a/ibm_platform_services/account_management_v4.py b/ibm_platform_services/account_management_v4.py new file mode 100644 index 0000000..d58a0b3 --- /dev/null +++ b/ibm_platform_services/account_management_v4.py @@ -0,0 +1,355 @@ +# coding: utf-8 + +# (C) Copyright IBM Corp. 2026. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# IBM OpenAPI SDK Code Generator Version: 3.111.0-1bfb72c2-20260206-185521 + +""" +The Account Management API allows for the management of Account + +API Version: 4.0.0 +""" + +from typing import Dict +import json + +from ibm_cloud_sdk_core import BaseService, DetailedResponse +from ibm_cloud_sdk_core.authenticators.authenticator import Authenticator +from ibm_cloud_sdk_core.get_authenticator import get_authenticator_from_environment + +from .common import get_sdk_headers + +############################################################################## +# Service +############################################################################## + + +class AccountManagementV4(BaseService): + """The account_management V4 service.""" + + DEFAULT_SERVICE_URL = 'https://accounts.cloud.ibm.com' + DEFAULT_SERVICE_NAME = 'account_management' + + @classmethod + def new_instance( + cls, + service_name: str = DEFAULT_SERVICE_NAME, + ) -> 'AccountManagementV4': + """ + Return a new client for the account_management service using the specified + parameters and external configuration. + """ + authenticator = get_authenticator_from_environment(service_name) + service = cls(authenticator) + service.configure_service(service_name) + return service + + def __init__( + self, + authenticator: Authenticator = None, + ) -> None: + """ + Construct a new client for the account_management service. + + :param Authenticator authenticator: The authenticator specifies the authentication mechanism. + Get up to date information from https://github.com/IBM/python-sdk-core/blob/main/README.md + about initializing the authenticator of your choice. + """ + BaseService.__init__(self, service_url=self.DEFAULT_SERVICE_URL, authenticator=authenticator) + + ######################### + # default + ######################### + + def get_account( + self, + account_id: str, + **kwargs, + ) -> DetailedResponse: + """ + Get Account by Account ID. + + Returns the details of an account. + + :param str account_id: The unique identifier of the account you want to + retrieve. + :param dict headers: A `dict` containing the request headers + :return: A `DetailedResponse` containing the result, headers and HTTP status code. + :rtype: DetailedResponse with `dict` result representing a `AccountResponse` object + """ + + if not account_id: + raise ValueError('account_id must be provided') + headers = {} + sdk_headers = get_sdk_headers( + service_name=self.DEFAULT_SERVICE_NAME, + service_version='V4', + operation_id='get_account', + ) + headers.update(sdk_headers) + + if 'headers' in kwargs: + headers.update(kwargs.get('headers')) + del kwargs['headers'] + headers['Accept'] = 'application/json' + + path_param_keys = ['account_id'] + path_param_values = self.encode_path_vars(account_id) + path_param_dict = dict(zip(path_param_keys, path_param_values)) + url = '/v4/accounts/{account_id}'.format(**path_param_dict) + request = self.prepare_request( + method='GET', + url=url, + headers=headers, + ) + + response = self.send(request, **kwargs) + return response + + +############################################################################## +# Models +############################################################################## + + +class AccountResponseTraits: + """ + AccountResponseTraits. + + :param bool eu_supported: + :param bool poc: + :param bool hippa: + """ + + def __init__( + self, + eu_supported: bool, + poc: bool, + hippa: bool, + ) -> None: + """ + Initialize a AccountResponseTraits object. + + :param bool eu_supported: + :param bool poc: + :param bool hippa: + """ + self.eu_supported = eu_supported + self.poc = poc + self.hippa = hippa + + @classmethod + def from_dict(cls, _dict: Dict) -> 'AccountResponseTraits': + """Initialize a AccountResponseTraits object from a json dictionary.""" + args = {} + if (eu_supported := _dict.get('eu_supported')) is not None: + args['eu_supported'] = eu_supported + else: + raise ValueError('Required property \'eu_supported\' not present in AccountResponseTraits JSON') + if (poc := _dict.get('poc')) is not None: + args['poc'] = poc + else: + raise ValueError('Required property \'poc\' not present in AccountResponseTraits JSON') + if (hippa := _dict.get('hippa')) is not None: + args['hippa'] = hippa + else: + raise ValueError('Required property \'hippa\' not present in AccountResponseTraits JSON') + return cls(**args) + + @classmethod + def _from_dict(cls, _dict): + """Initialize a AccountResponseTraits object from a json dictionary.""" + return cls.from_dict(_dict) + + def to_dict(self) -> Dict: + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'eu_supported') and self.eu_supported is not None: + _dict['eu_supported'] = self.eu_supported + if hasattr(self, 'poc') and self.poc is not None: + _dict['poc'] = self.poc + if hasattr(self, 'hippa') and self.hippa is not None: + _dict['hippa'] = self.hippa + return _dict + + def _to_dict(self): + """Return a json dictionary representing this model.""" + return self.to_dict() + + def __str__(self) -> str: + """Return a `str` version of this AccountResponseTraits object.""" + return json.dumps(self.to_dict(), indent=2) + + def __eq__(self, other: 'AccountResponseTraits') -> bool: + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other: 'AccountResponseTraits') -> bool: + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other + + +class AccountResponse: + """ + AccountResponse. + + :param str name: + :param str id: + :param str owner: + :param str owner_userid: + :param str owner_iamid: + :param str type: + :param str status: + :param str linked_softlayer_account: + :param bool team_directory_enabled: + :param AccountResponseTraits traits: + """ + + def __init__( + self, + name: str, + id: str, + owner: str, + owner_userid: str, + owner_iamid: str, + type: str, + status: str, + linked_softlayer_account: str, + team_directory_enabled: bool, + traits: 'AccountResponseTraits', + ) -> None: + """ + Initialize a AccountResponse object. + + :param str name: + :param str id: + :param str owner: + :param str owner_userid: + :param str owner_iamid: + :param str type: + :param str status: + :param str linked_softlayer_account: + :param bool team_directory_enabled: + :param AccountResponseTraits traits: + """ + self.name = name + self.id = id + self.owner = owner + self.owner_userid = owner_userid + self.owner_iamid = owner_iamid + self.type = type + self.status = status + self.linked_softlayer_account = linked_softlayer_account + self.team_directory_enabled = team_directory_enabled + self.traits = traits + + @classmethod + def from_dict(cls, _dict: Dict) -> 'AccountResponse': + """Initialize a AccountResponse object from a json dictionary.""" + args = {} + if (name := _dict.get('name')) is not None: + args['name'] = name + else: + raise ValueError('Required property \'name\' not present in AccountResponse JSON') + if (id := _dict.get('id')) is not None: + args['id'] = id + else: + raise ValueError('Required property \'id\' not present in AccountResponse JSON') + if (owner := _dict.get('owner')) is not None: + args['owner'] = owner + else: + raise ValueError('Required property \'owner\' not present in AccountResponse JSON') + if (owner_userid := _dict.get('owner_userid')) is not None: + args['owner_userid'] = owner_userid + else: + raise ValueError('Required property \'owner_userid\' not present in AccountResponse JSON') + if (owner_iamid := _dict.get('owner_iamid')) is not None: + args['owner_iamid'] = owner_iamid + else: + raise ValueError('Required property \'owner_iamid\' not present in AccountResponse JSON') + if (type := _dict.get('type')) is not None: + args['type'] = type + else: + raise ValueError('Required property \'type\' not present in AccountResponse JSON') + if (status := _dict.get('status')) is not None: + args['status'] = status + else: + raise ValueError('Required property \'status\' not present in AccountResponse JSON') + if (linked_softlayer_account := _dict.get('linked_softlayer_account')) is not None: + args['linked_softlayer_account'] = linked_softlayer_account + else: + raise ValueError('Required property \'linked_softlayer_account\' not present in AccountResponse JSON') + if (team_directory_enabled := _dict.get('team_directory_enabled')) is not None: + args['team_directory_enabled'] = team_directory_enabled + else: + raise ValueError('Required property \'team_directory_enabled\' not present in AccountResponse JSON') + if (traits := _dict.get('traits')) is not None: + args['traits'] = AccountResponseTraits.from_dict(traits) + else: + raise ValueError('Required property \'traits\' not present in AccountResponse JSON') + return cls(**args) + + @classmethod + def _from_dict(cls, _dict): + """Initialize a AccountResponse object from a json dictionary.""" + return cls.from_dict(_dict) + + def to_dict(self) -> Dict: + """Return a json dictionary representing this model.""" + _dict = {} + if hasattr(self, 'name') and self.name is not None: + _dict['name'] = self.name + if hasattr(self, 'id') and self.id is not None: + _dict['id'] = self.id + if hasattr(self, 'owner') and self.owner is not None: + _dict['owner'] = self.owner + if hasattr(self, 'owner_userid') and self.owner_userid is not None: + _dict['owner_userid'] = self.owner_userid + if hasattr(self, 'owner_iamid') and self.owner_iamid is not None: + _dict['owner_iamid'] = self.owner_iamid + if hasattr(self, 'type') and self.type is not None: + _dict['type'] = self.type + if hasattr(self, 'status') and self.status is not None: + _dict['status'] = self.status + if hasattr(self, 'linked_softlayer_account') and self.linked_softlayer_account is not None: + _dict['linked_softlayer_account'] = self.linked_softlayer_account + if hasattr(self, 'team_directory_enabled') and self.team_directory_enabled is not None: + _dict['team_directory_enabled'] = self.team_directory_enabled + if hasattr(self, 'traits') and self.traits is not None: + if isinstance(self.traits, dict): + _dict['traits'] = self.traits + else: + _dict['traits'] = self.traits.to_dict() + return _dict + + def _to_dict(self): + """Return a json dictionary representing this model.""" + return self.to_dict() + + def __str__(self) -> str: + """Return a `str` version of this AccountResponse object.""" + return json.dumps(self.to_dict(), indent=2) + + def __eq__(self, other: 'AccountResponse') -> bool: + """Return `true` when self and other are equal, false otherwise.""" + if not isinstance(other, self.__class__): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other: 'AccountResponse') -> bool: + """Return `true` when self and other are not equal, false otherwise.""" + return not self == other diff --git a/test/integration/test_account_management_v4.py b/test/integration/test_account_management_v4.py new file mode 100644 index 0000000..b13bf0a --- /dev/null +++ b/test/integration/test_account_management_v4.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# (C) Copyright IBM Corp. 2026. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Integration Tests for AccountManagementV4 +""" + +from ibm_cloud_sdk_core import * +import os +import pytest +from ibm_platform_services.account_management_v4 import * + +# Config file name +config_file = 'account_management_v4.env' +account_id = None + + +class TestAccountManagementV4: + """ + Integration Test Class for AccountManagementV4 + """ + + @classmethod + def setup_class(cls): + if os.path.exists(config_file): + os.environ['IBM_CREDENTIALS_FILE'] = config_file + + cls.account_management_service = AccountManagementV4.new_instance() + assert cls.account_management_service is not None + + cls.config = read_external_sources(AccountManagementV4.DEFAULT_SERVICE_NAME) + assert cls.config is not None + global account_id + account_id = cls.config['ACCOUNT_ID'] + + cls.account_management_service.enable_retries() + + print('Setup complete.') + + needscredentials = pytest.mark.skipif( + not os.path.exists(config_file), reason="External configuration not available, skipping..." + ) + + @needscredentials + def test_get_account(self): + response = self.account_management_service.get_account( + account_id=account_id, + ) + + assert response.get_status_code() == 200 + account_response = response.get_result() + assert account_response is not None diff --git a/test/unit/test_account_management_v4.py b/test/unit/test_account_management_v4.py new file mode 100644 index 0000000..b7270c5 --- /dev/null +++ b/test/unit/test_account_management_v4.py @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- +# (C) Copyright IBM Corp. 2026. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Unit Tests for AccountManagementV4 +""" + +from ibm_cloud_sdk_core.authenticators.no_auth_authenticator import NoAuthAuthenticator +import inspect +import json +import os +import pytest +import re +import responses +import urllib +from ibm_platform_services.account_management_v4 import * + + +_service = AccountManagementV4(authenticator=NoAuthAuthenticator()) + +_base_url = 'https://accounts.test.cloud.ibm.com' +_service.set_service_url(_base_url) + + +def preprocess_url(operation_path: str): + """ + Returns the request url associated with the specified operation path. + This will be base_url concatenated with a quoted version of operation_path. + The returned request URL is used to register the mock response so it needs + to match the request URL that is formed by the requests library. + """ + + # Form the request URL from the base URL and operation path. + request_url = _base_url + operation_path + + # If the request url does NOT end with a /, then just return it as-is. + # Otherwise, return a regular expression that matches one or more trailing /. + if not request_url.endswith('/'): + return request_url + return re.compile(request_url.rstrip('/') + '/+') + + +############################################################################## +# Start of Service: Default +############################################################################## +# region + + +class TestNewInstance: + """ + Test Class for new_instance + """ + + def test_new_instance(self): + """ + new_instance() + """ + os.environ['TEST_SERVICE_AUTH_TYPE'] = 'noAuth' + + service = AccountManagementV4.new_instance( + service_name='TEST_SERVICE', + ) + + assert service is not None + assert isinstance(service, AccountManagementV4) + + def test_new_instance_without_authenticator(self): + """ + new_instance_without_authenticator() + """ + with pytest.raises(ValueError, match='authenticator must be provided'): + service = AccountManagementV4.new_instance( + service_name='TEST_SERVICE_NOT_FOUND', + ) + + +class TestGetAccount: + """ + Test Class for get_account + """ + + @responses.activate + def test_get_account_all_params(self): + """ + get_account() + """ + # Set up mock + url = preprocess_url('/v4/accounts/testString') + mock_response = '{"name": "name", "id": "id", "owner": "owner", "owner_userid": "owner_userid", "owner_iamid": "owner_iamid", "type": "type", "status": "status", "linked_softlayer_account": "linked_softlayer_account", "team_directory_enabled": true, "traits": {"eu_supported": true, "poc": false, "hippa": false}}' + responses.add( + responses.GET, + url, + body=mock_response, + content_type='application/json', + status=200, + ) + + # Set up parameter values + account_id = 'testString' + + # Invoke method + response = _service.get_account( + account_id, + headers={}, + ) + + # Check for correct operation + assert len(responses.calls) == 1 + assert response.status_code == 200 + + def test_get_account_all_params_with_retries(self): + # Enable retries and run test_get_account_all_params. + _service.enable_retries() + self.test_get_account_all_params() + + # Disable retries and run test_get_account_all_params. + _service.disable_retries() + self.test_get_account_all_params() + + @responses.activate + def test_get_account_value_error(self): + """ + test_get_account_value_error() + """ + # Set up mock + url = preprocess_url('/v4/accounts/testString') + mock_response = '{"name": "name", "id": "id", "owner": "owner", "owner_userid": "owner_userid", "owner_iamid": "owner_iamid", "type": "type", "status": "status", "linked_softlayer_account": "linked_softlayer_account", "team_directory_enabled": true, "traits": {"eu_supported": true, "poc": false, "hippa": false}}' + responses.add( + responses.GET, + url, + body=mock_response, + content_type='application/json', + status=200, + ) + + # Set up parameter values + account_id = 'testString' + + # Pass in all but one required param and check for a ValueError + req_param_dict = { + "account_id": account_id, + } + for param in req_param_dict.keys(): + req_copy = {key: val if key is not param else None for (key, val) in req_param_dict.items()} + with pytest.raises(ValueError): + _service.get_account(**req_copy) + + def test_get_account_value_error_with_retries(self): + # Enable retries and run test_get_account_value_error. + _service.enable_retries() + self.test_get_account_value_error() + + # Disable retries and run test_get_account_value_error. + _service.disable_retries() + self.test_get_account_value_error() + + +# endregion +############################################################################## +# End of Service: Default +############################################################################## + + +############################################################################## +# Start of Model Tests +############################################################################## +# region + + +class TestModel_AccountResponseTraits: + """ + Test Class for AccountResponseTraits + """ + + def test_account_response_traits_serialization(self): + """ + Test serialization/deserialization for AccountResponseTraits + """ + + # Construct a json representation of a AccountResponseTraits model + account_response_traits_model_json = {} + account_response_traits_model_json['eu_supported'] = True + account_response_traits_model_json['poc'] = True + account_response_traits_model_json['hippa'] = True + + # Construct a model instance of AccountResponseTraits by calling from_dict on the json representation + account_response_traits_model = AccountResponseTraits.from_dict(account_response_traits_model_json) + assert account_response_traits_model != False + + # Construct a model instance of AccountResponseTraits by calling from_dict on the json representation + account_response_traits_model_dict = AccountResponseTraits.from_dict( + account_response_traits_model_json + ).__dict__ + account_response_traits_model2 = AccountResponseTraits(**account_response_traits_model_dict) + + # Verify the model instances are equivalent + assert account_response_traits_model == account_response_traits_model2 + + # Convert model instance back to dict and verify no loss of data + account_response_traits_model_json2 = account_response_traits_model.to_dict() + assert account_response_traits_model_json2 == account_response_traits_model_json + + +class TestModel_AccountResponse: + """ + Test Class for AccountResponse + """ + + def test_account_response_serialization(self): + """ + Test serialization/deserialization for AccountResponse + """ + + # Construct dict forms of any model objects needed in order to build this model. + + account_response_traits_model = {} # AccountResponseTraits + account_response_traits_model['eu_supported'] = True + account_response_traits_model['poc'] = True + account_response_traits_model['hippa'] = True + + # Construct a json representation of a AccountResponse model + account_response_model_json = {} + account_response_model_json['name'] = 'testString' + account_response_model_json['id'] = 'testString' + account_response_model_json['owner'] = 'testString' + account_response_model_json['owner_userid'] = 'testString' + account_response_model_json['owner_iamid'] = 'testString' + account_response_model_json['type'] = 'testString' + account_response_model_json['status'] = 'testString' + account_response_model_json['linked_softlayer_account'] = 'testString' + account_response_model_json['team_directory_enabled'] = True + account_response_model_json['traits'] = account_response_traits_model + + # Construct a model instance of AccountResponse by calling from_dict on the json representation + account_response_model = AccountResponse.from_dict(account_response_model_json) + assert account_response_model != False + + # Construct a model instance of AccountResponse by calling from_dict on the json representation + account_response_model_dict = AccountResponse.from_dict(account_response_model_json).__dict__ + account_response_model2 = AccountResponse(**account_response_model_dict) + + # Verify the model instances are equivalent + assert account_response_model == account_response_model2 + + # Convert model instance back to dict and verify no loss of data + account_response_model_json2 = account_response_model.to_dict() + assert account_response_model_json2 == account_response_model_json + + +# endregion +############################################################################## +# End of Model Tests +##############################################################################