Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move exceptions into their own python module #1246

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/20221104-exceptions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- module_utils - move exceptions into dedicated python module (https://github.com/ansible-collections/amazon.aws/pull/1246).
7 changes: 3 additions & 4 deletions plugins/module_utils/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
from .botocore import get_boto3_client_method_parameters # pylint: disable=unused-import
from .botocore import normalize_boto3_result # pylint: disable=unused-import

# Used to live here, moved into ansible_collections.amazon.aws.plugins.module_utils.exceptions
from .exceptions import AnsibleAWSError # pylint: disable=unused-import

# Used to live here, moved into ansible_collections.amazon.aws.plugins.module_utils.modules
from .modules import AnsibleAWSModule # pylint: disable=unused-import

Expand All @@ -71,7 +74,3 @@

# We will also export HAS_BOTO3 so end user modules can use it.
__all__ = ('AnsibleAWSModule', 'HAS_BOTO3', 'is_boto3_error_code', 'is_boto3_error_message')


class AnsibleAWSError(Exception):
pass
38 changes: 38 additions & 0 deletions plugins/module_utils/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# (c) 2022 Red Hat Inc.
#
# This file is part of Ansible
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.module_utils._text import to_native


class AnsibleAWSError(Exception):

def __str__(self):
if self.exception and self.message:
return "{0}: {1}".format(self.message, to_native(self.exception))

return super().__str__()

def __init__(self, message=None, exception=None, **kwargs):
if not message and not exception:
super().__init__()
elif not message:
super().__init__(exception)
else:
super().__init__(message)

self.exception = exception
self.message = message

# In places where passing more information to module.fail_json would be helpful
# store the extra info. Other plugin types have to raise the correct exception
# such as AnsibleLookupError, so can't easily consume this.
self.kwargs = kwargs or {}


class AnsibleBotocoreError(AnsibleAWSError):
pass
101 changes: 101 additions & 0 deletions tests/unit/module_utils/exceptions/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# (c) 2022 Red Hat Inc.
#
# This file is part of Ansible
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import pytest
from unittest.mock import sentinel

import ansible_collections.amazon.aws.plugins.module_utils.exceptions as aws_exceptions


@pytest.fixture
def utils_exceptions():
return aws_exceptions


def test_with_kwargs(utils_exceptions):
nested_exception = Exception(sentinel.EXCEPTION)
with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError(kw1=sentinel.KW1, kw2=sentinel.KW2)
assert str(e.value) == ''
assert e.value.exception is None
assert e.value.message is None
assert e.value.kwargs == dict(kw1=sentinel.KW1, kw2=sentinel.KW2)

with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError(message=sentinel.MESSAGE, exception=nested_exception, kw1=sentinel.KW1, kw2=sentinel.KW2)
assert str(e.value) == 'sentinel.MESSAGE: sentinel.EXCEPTION'
assert e.value.exception is nested_exception
assert e.value.message is sentinel.MESSAGE
assert e.value.kwargs == dict(kw1=sentinel.KW1, kw2=sentinel.KW2)


def test_with_both(utils_exceptions):
nested_exception = Exception(sentinel.EXCEPTION)

with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError(message=sentinel.MESSAGE, exception=nested_exception)
assert str(e.value) == 'sentinel.MESSAGE: sentinel.EXCEPTION'
assert e.value.exception is nested_exception
assert e.value.message is sentinel.MESSAGE
assert e.value.kwargs == {}

with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError(sentinel.MESSAGE, exception=nested_exception)
assert str(e.value) == 'sentinel.MESSAGE: sentinel.EXCEPTION'
assert e.value.exception is nested_exception
assert e.value.message is sentinel.MESSAGE
assert e.value.kwargs == {}


def test_with_exception(utils_exceptions):
nested_exception = Exception(sentinel.EXCEPTION)

with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError(exception=nested_exception)
assert str(e.value) == 'sentinel.EXCEPTION'
assert e.value.exception is nested_exception
assert e.value.message is None
assert e.value.kwargs == {}


def test_with_message(utils_exceptions):
with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError(message=sentinel.MESSAGE)
assert str(e.value) == 'sentinel.MESSAGE'
assert e.value.exception is None
assert e.value.message is sentinel.MESSAGE
assert e.value.kwargs == {}

with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError(sentinel.MESSAGE)
assert str(e.value) == 'sentinel.MESSAGE'
assert e.value.exception is None
assert e.value.message is sentinel.MESSAGE
assert e.value.kwargs == {}


def test_empty(utils_exceptions):
with pytest.raises(utils_exceptions.AnsibleAWSError) as e:
raise utils_exceptions.AnsibleAWSError()
assert str(e.value) == ''
assert e.value.exception is None
assert e.value.message is None
assert e.value.kwargs == {}


def test_inheritence(utils_exceptions):
aws_exception = utils_exceptions.AnsibleAWSError()

assert isinstance(aws_exception, Exception)
assert isinstance(aws_exception, utils_exceptions.AnsibleAWSError)

botocore_exception = utils_exceptions.AnsibleBotocoreError()

assert isinstance(botocore_exception, Exception)
assert isinstance(botocore_exception, utils_exceptions.AnsibleAWSError)
assert isinstance(botocore_exception, utils_exceptions.AnsibleBotocoreError)