From ddb3300ff3535a61d02371dc04087755d1d86bb4 Mon Sep 17 00:00:00 2001 From: Joe Gordon Date: Mon, 18 Dec 2023 16:50:30 -0800 Subject: [PATCH 1/6] Speed up exception handling by re-using Environments Address https://github.com/getmoto/moto/issues/7142 --- moto/cloudfront/exceptions.py | 4 +++- moto/core/exceptions.py | 4 ++-- moto/ec2/exceptions.py | 4 +++- moto/elasticache/exceptions.py | 3 +++ moto/elasticbeanstalk/exceptions.py | 3 +++ moto/s3/exceptions.py | 12 ++++++++++++ moto/s3control/exceptions.py | 9 +++++++-- moto/sagemaker/exceptions.py | 5 ++++- moto/sdb/exceptions.py | 6 +++++- 9 files changed, 42 insertions(+), 8 deletions(-) diff --git a/moto/cloudfront/exceptions.py b/moto/cloudfront/exceptions.py index 584d999e4d7a..65cd219d534c 100644 --- a/moto/cloudfront/exceptions.py +++ b/moto/cloudfront/exceptions.py @@ -1,5 +1,6 @@ from typing import Any +from jinja2 import DictLoader, Environment from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -15,10 +16,11 @@ class CloudFrontException(RESTError): code = 400 + extended_templates = {"cferror": EXCEPTION_RESPONSE} + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) def __init__(self, error_type: str, message: str, **kwargs: Any): kwargs.setdefault("template", "cferror") - self.templates["cferror"] = EXCEPTION_RESPONSE super().__init__(error_type, message, **kwargs) diff --git a/moto/core/exceptions.py b/moto/core/exceptions.py index ee9a07820a0b..30e77084a34b 100644 --- a/moto/core/exceptions.py +++ b/moto/core/exceptions.py @@ -54,6 +54,7 @@ class RESTError(HTTPException): "wrapped_single_error": WRAPPED_SINGLE_ERROR_RESPONSE, "error": ERROR_RESPONSE, } + env = Environment(loader=DictLoader(templates)) def __init__( self, error_type: str, message: str, template: str = "error", **kwargs: Any @@ -63,8 +64,7 @@ def __init__( self.message = message if template in self.templates.keys(): - env = Environment(loader=DictLoader(self.templates)) - self.description: str = env.get_template(template).render( + self.description: str = self.env.get_template(template).render( error_type=error_type, message=message, request_id_tag=self.request_id_tag_name, diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py index c9354d3fb1ea..e103dcb6e4c4 100644 --- a/moto/ec2/exceptions.py +++ b/moto/ec2/exceptions.py @@ -1,5 +1,6 @@ from typing import Any, Iterable, List, Optional, Union +from jinja2 import DictLoader, Environment from moto.core.exceptions import RESTError # EC2 has a custom root-tag - vs @@ -22,10 +23,11 @@ class EC2ClientError(RESTError): code = 400 # EC2 uses as tag name in the XML response request_id_tag_name = "RequestID" + extended_templates = {"custom_response": EC2_ERROR_RESPONSE} + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "custom_response") - self.templates["custom_response"] = EC2_ERROR_RESPONSE super().__init__(*args, **kwargs) diff --git a/moto/elasticache/exceptions.py b/moto/elasticache/exceptions.py index f5e7f5b65413..ab5e2cd4153d 100644 --- a/moto/elasticache/exceptions.py +++ b/moto/elasticache/exceptions.py @@ -1,5 +1,6 @@ from typing import Any +from jinja2 import DictLoader, Environment from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -16,6 +17,8 @@ class ElastiCacheException(RESTError): code = 400 + extended_templates = {"ecerror": EXCEPTION_RESPONSE} + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) def __init__(self, code: str, message: str, **kwargs: Any): kwargs.setdefault("template", "ecerror") diff --git a/moto/elasticbeanstalk/exceptions.py b/moto/elasticbeanstalk/exceptions.py index 632080fb5f7b..c210b7aaea9b 100644 --- a/moto/elasticbeanstalk/exceptions.py +++ b/moto/elasticbeanstalk/exceptions.py @@ -1,5 +1,6 @@ from typing import Any +from jinja2 import DictLoader, Environment from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -16,6 +17,8 @@ class ElasticBeanstalkException(RESTError): code = 400 + extended_templates = {"ecerror": EXCEPTION_RESPONSE} + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) def __init__(self, code: str, message: str, **kwargs: Any): kwargs.setdefault("template", "ecerror") diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py index b86d56995c50..fbbce0f02b1f 100644 --- a/moto/s3/exceptions.py +++ b/moto/s3/exceptions.py @@ -1,5 +1,6 @@ from typing import TYPE_CHECKING, Any, Optional, Union +from jinja2 import DictLoader, Environment from moto.core.exceptions import RESTError if TYPE_CHECKING: @@ -41,6 +42,17 @@ class S3ClientError(RESTError): # S3 API uses as the XML tag in response messages request_id_tag_name = "RequestID" + extended_templates = { + "bucket_error": ERROR_WITH_BUCKET_NAME, + "key_error": ERROR_WITH_KEY_NAME, + "argument_error": ERROR_WITH_ARGUMENT, + "error_uploadid": ERROR_WITH_UPLOADID, + "condition_error": ERROR_WITH_CONDITION_NAME, + "range_error": ERROR_WITH_RANGE, + "storage_error": ERROR_WITH_STORAGE_CLASS, + } + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") self.templates["bucket_error"] = ERROR_WITH_BUCKET_NAME diff --git a/moto/s3control/exceptions.py b/moto/s3control/exceptions.py index 05d962f50d60..fa2b1389b7ef 100644 --- a/moto/s3control/exceptions.py +++ b/moto/s3control/exceptions.py @@ -1,5 +1,6 @@ from typing import Any +from jinja2 import DictLoader, Environment from moto.core.exceptions import RESTError ERROR_WITH_ACCESS_POINT_NAME = """{% extends 'wrapped_single_error' %} @@ -13,6 +14,12 @@ class S3ControlError(RESTError): + extended_templates = { + "ap_not_found": ERROR_WITH_ACCESS_POINT_NAME, + "apf_not_found": ERROR_WITH_ACCESS_POINT_POLICY, + } + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") super().__init__(*args, **kwargs) @@ -24,7 +31,6 @@ class AccessPointNotFound(S3ControlError): def __init__(self, name: str, **kwargs: Any): kwargs.setdefault("template", "ap_not_found") kwargs["name"] = name - self.templates["ap_not_found"] = ERROR_WITH_ACCESS_POINT_NAME super().__init__( "NoSuchAccessPoint", "The specified accesspoint does not exist", **kwargs ) @@ -36,7 +42,6 @@ class AccessPointPolicyNotFound(S3ControlError): def __init__(self, name: str, **kwargs: Any): kwargs.setdefault("template", "apf_not_found") kwargs["name"] = name - self.templates["apf_not_found"] = ERROR_WITH_ACCESS_POINT_POLICY super().__init__( "NoSuchAccessPointPolicy", "The specified accesspoint policy does not exist", diff --git a/moto/sagemaker/exceptions.py b/moto/sagemaker/exceptions.py index 77e9308627d6..febb7f712f7c 100644 --- a/moto/sagemaker/exceptions.py +++ b/moto/sagemaker/exceptions.py @@ -1,5 +1,6 @@ from typing import Any +from jinja2 import DictLoader, Environment from moto.core.exceptions import AWSError, JsonRESTError, RESTError ERROR_WITH_MODEL_NAME = """{% extends 'single_error' %} @@ -8,9 +9,11 @@ class SagemakerClientError(RESTError): + extended_templates = {"model_error": ERROR_WITH_MODEL_NAME} + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") - self.templates["model_error"] = ERROR_WITH_MODEL_NAME super().__init__(*args, **kwargs) diff --git a/moto/sdb/exceptions.py b/moto/sdb/exceptions.py index 9d90ecddc899..2315c9914574 100644 --- a/moto/sdb/exceptions.py +++ b/moto/sdb/exceptions.py @@ -2,6 +2,7 @@ from typing import Any from moto.core.exceptions import RESTError +from jinja2 import DictLoader, Environment SDB_ERROR = """ @@ -18,6 +19,8 @@ class InvalidParameterError(RESTError): code = 400 + extended_templates = {"sdb_error": SDB_ERROR} + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) def __init__(self, **kwargs: Any): kwargs.setdefault("template", "sdb_error") @@ -37,10 +40,11 @@ def __init__(self, domain_name: str): class UnknownDomainName(RESTError): code = 400 + extended_templates = {"sdb_error": SDB_ERROR} + env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) def __init__(self, **kwargs: Any): kwargs.setdefault("template", "sdb_error") - self.templates["sdb_error"] = SDB_ERROR kwargs["error_type"] = "NoSuchDomain" kwargs["message"] = "The specified domain does not exist." super().__init__(**kwargs) From f994292cdda57622ffbd47568e9a151bff72cdee Mon Sep 17 00:00:00 2001 From: Joe Gordon Date: Tue, 19 Dec 2023 07:31:29 -0800 Subject: [PATCH 2/6] cleanup --- moto/cloudfront/exceptions.py | 5 ++++- moto/core/exceptions.py | 10 ++++++++-- moto/ec2/exceptions.py | 5 ++++- moto/elasticache/exceptions.py | 6 ++++-- moto/elasticbeanstalk/exceptions.py | 5 ++++- moto/s3/exceptions.py | 5 ++++- moto/s3control/exceptions.py | 5 ++++- moto/sagemaker/exceptions.py | 5 ++++- moto/sdb/exceptions.py | 11 ++++++++--- 9 files changed, 44 insertions(+), 13 deletions(-) diff --git a/moto/cloudfront/exceptions.py b/moto/cloudfront/exceptions.py index 65cd219d534c..8fd85bef0409 100644 --- a/moto/cloudfront/exceptions.py +++ b/moto/cloudfront/exceptions.py @@ -1,6 +1,7 @@ from typing import Any from jinja2 import DictLoader, Environment + from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -17,7 +18,9 @@ class CloudFrontException(RESTError): code = 400 extended_templates = {"cferror": EXCEPTION_RESPONSE} - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, error_type: str, message: str, **kwargs: Any): kwargs.setdefault("template", "cferror") diff --git a/moto/core/exceptions.py b/moto/core/exceptions.py index 30e77084a34b..587415fa0ea3 100644 --- a/moto/core/exceptions.py +++ b/moto/core/exceptions.py @@ -1,5 +1,5 @@ import json -from typing import Any, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple from jinja2 import DictLoader, Environment from werkzeug.exceptions import HTTPException @@ -64,7 +64,7 @@ def __init__( self.message = message if template in self.templates.keys(): - self.description: str = self.env.get_template(template).render( + self.description: str = self.__class__.env.get_template(template).render( error_type=error_type, message=message, request_id_tag=self.request_id_tag_name, @@ -95,6 +95,12 @@ def to_json(self) -> "JsonRESTError": err.code = self.code return err + @classmethod + def extended_templates(cls, extended_templates: Dict) -> Dict: + # Can be simplified to cls.templates | extended_templates when we drop Python 3.8 support + # https://docs.python.org/3/library/stdtypes.html#mapping-types-dict + return dict(cls.templates.items() | extended_templates.items()) + class DryRunClientError(RESTError): code = 412 diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py index e103dcb6e4c4..7a1949b50003 100644 --- a/moto/ec2/exceptions.py +++ b/moto/ec2/exceptions.py @@ -1,6 +1,7 @@ from typing import Any, Iterable, List, Optional, Union from jinja2 import DictLoader, Environment + from moto.core.exceptions import RESTError # EC2 has a custom root-tag - vs @@ -24,7 +25,9 @@ class EC2ClientError(RESTError): # EC2 uses as tag name in the XML response request_id_tag_name = "RequestID" extended_templates = {"custom_response": EC2_ERROR_RESPONSE} - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "custom_response") diff --git a/moto/elasticache/exceptions.py b/moto/elasticache/exceptions.py index ab5e2cd4153d..754d28f2bf2c 100644 --- a/moto/elasticache/exceptions.py +++ b/moto/elasticache/exceptions.py @@ -1,6 +1,7 @@ from typing import Any from jinja2 import DictLoader, Environment + from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -18,11 +19,12 @@ class ElastiCacheException(RESTError): code = 400 extended_templates = {"ecerror": EXCEPTION_RESPONSE} - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, code: str, message: str, **kwargs: Any): kwargs.setdefault("template", "ecerror") - self.templates["ecerror"] = EXCEPTION_RESPONSE super().__init__(code, message) diff --git a/moto/elasticbeanstalk/exceptions.py b/moto/elasticbeanstalk/exceptions.py index c210b7aaea9b..8c2cc2f5cf7b 100644 --- a/moto/elasticbeanstalk/exceptions.py +++ b/moto/elasticbeanstalk/exceptions.py @@ -1,6 +1,7 @@ from typing import Any from jinja2 import DictLoader, Environment + from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -18,7 +19,9 @@ class ElasticBeanstalkException(RESTError): code = 400 extended_templates = {"ecerror": EXCEPTION_RESPONSE} - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, code: str, message: str, **kwargs: Any): kwargs.setdefault("template", "ecerror") diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py index fbbce0f02b1f..6a5d85d84c1c 100644 --- a/moto/s3/exceptions.py +++ b/moto/s3/exceptions.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING, Any, Optional, Union from jinja2 import DictLoader, Environment + from moto.core.exceptions import RESTError if TYPE_CHECKING: @@ -51,7 +52,9 @@ class S3ClientError(RESTError): "range_error": ERROR_WITH_RANGE, "storage_error": ERROR_WITH_STORAGE_CLASS, } - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") diff --git a/moto/s3control/exceptions.py b/moto/s3control/exceptions.py index fa2b1389b7ef..fd5f1686dcbc 100644 --- a/moto/s3control/exceptions.py +++ b/moto/s3control/exceptions.py @@ -1,6 +1,7 @@ from typing import Any from jinja2 import DictLoader, Environment + from moto.core.exceptions import RESTError ERROR_WITH_ACCESS_POINT_NAME = """{% extends 'wrapped_single_error' %} @@ -18,7 +19,9 @@ class S3ControlError(RESTError): "ap_not_found": ERROR_WITH_ACCESS_POINT_NAME, "apf_not_found": ERROR_WITH_ACCESS_POINT_POLICY, } - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") diff --git a/moto/sagemaker/exceptions.py b/moto/sagemaker/exceptions.py index febb7f712f7c..b83f7d25064d 100644 --- a/moto/sagemaker/exceptions.py +++ b/moto/sagemaker/exceptions.py @@ -1,6 +1,7 @@ from typing import Any from jinja2 import DictLoader, Environment + from moto.core.exceptions import AWSError, JsonRESTError, RESTError ERROR_WITH_MODEL_NAME = """{% extends 'single_error' %} @@ -10,7 +11,9 @@ class SagemakerClientError(RESTError): extended_templates = {"model_error": ERROR_WITH_MODEL_NAME} - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") diff --git a/moto/sdb/exceptions.py b/moto/sdb/exceptions.py index 2315c9914574..65c9221000c9 100644 --- a/moto/sdb/exceptions.py +++ b/moto/sdb/exceptions.py @@ -1,9 +1,10 @@ """Exceptions raised by the sdb service.""" from typing import Any -from moto.core.exceptions import RESTError from jinja2 import DictLoader, Environment +from moto.core.exceptions import RESTError + SDB_ERROR = """ @@ -20,7 +21,9 @@ class InvalidParameterError(RESTError): code = 400 extended_templates = {"sdb_error": SDB_ERROR} - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, **kwargs: Any): kwargs.setdefault("template", "sdb_error") @@ -41,7 +44,9 @@ def __init__(self, domain_name: str): class UnknownDomainName(RESTError): code = 400 extended_templates = {"sdb_error": SDB_ERROR} - env = Environment(loader=DictLoader(RESTError.templates | extended_templates)) + env = Environment( + loader=DictLoader(RESTError.extended_templates(extended_templates)) + ) def __init__(self, **kwargs: Any): kwargs.setdefault("template", "sdb_error") From 377ded238b84366e6e3d4de00dfc35b71ba63aba Mon Sep 17 00:00:00 2001 From: Joe Gordon Date: Tue, 19 Dec 2023 09:22:15 -0800 Subject: [PATCH 3/6] simplify --- moto/cloudfront/exceptions.py | 6 +----- moto/core/exceptions.py | 5 +++-- moto/ec2/exceptions.py | 6 +----- moto/elasticache/exceptions.py | 6 +----- moto/elasticbeanstalk/exceptions.py | 6 +----- moto/s3/exceptions.py | 6 +----- moto/s3control/exceptions.py | 6 +----- moto/sagemaker/exceptions.py | 6 +----- moto/sdb/exceptions.py | 10 ++-------- 9 files changed, 12 insertions(+), 45 deletions(-) diff --git a/moto/cloudfront/exceptions.py b/moto/cloudfront/exceptions.py index 8fd85bef0409..b8e7f634d92d 100644 --- a/moto/cloudfront/exceptions.py +++ b/moto/cloudfront/exceptions.py @@ -1,7 +1,5 @@ from typing import Any -from jinja2 import DictLoader, Environment - from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -18,9 +16,7 @@ class CloudFrontException(RESTError): code = 400 extended_templates = {"cferror": EXCEPTION_RESPONSE} - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, error_type: str, message: str, **kwargs: Any): kwargs.setdefault("template", "cferror") diff --git a/moto/core/exceptions.py b/moto/core/exceptions.py index 587415fa0ea3..c57003b78de2 100644 --- a/moto/core/exceptions.py +++ b/moto/core/exceptions.py @@ -96,10 +96,11 @@ def to_json(self) -> "JsonRESTError": return err @classmethod - def extended_templates(cls, extended_templates: Dict) -> Dict: + def extended_environment(cls, extended_templates: Dict) -> Environment: # Can be simplified to cls.templates | extended_templates when we drop Python 3.8 support # https://docs.python.org/3/library/stdtypes.html#mapping-types-dict - return dict(cls.templates.items() | extended_templates.items()) + templates = dict(cls.templates.items() | extended_templates.items()) + return Environment(loader=DictLoader(templates)) class DryRunClientError(RESTError): diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py index 7a1949b50003..8b8fc7f33349 100644 --- a/moto/ec2/exceptions.py +++ b/moto/ec2/exceptions.py @@ -1,7 +1,5 @@ from typing import Any, Iterable, List, Optional, Union -from jinja2 import DictLoader, Environment - from moto.core.exceptions import RESTError # EC2 has a custom root-tag - vs @@ -25,9 +23,7 @@ class EC2ClientError(RESTError): # EC2 uses as tag name in the XML response request_id_tag_name = "RequestID" extended_templates = {"custom_response": EC2_ERROR_RESPONSE} - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "custom_response") diff --git a/moto/elasticache/exceptions.py b/moto/elasticache/exceptions.py index 754d28f2bf2c..0d63efb884fa 100644 --- a/moto/elasticache/exceptions.py +++ b/moto/elasticache/exceptions.py @@ -1,7 +1,5 @@ from typing import Any -from jinja2 import DictLoader, Environment - from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -19,9 +17,7 @@ class ElastiCacheException(RESTError): code = 400 extended_templates = {"ecerror": EXCEPTION_RESPONSE} - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, code: str, message: str, **kwargs: Any): kwargs.setdefault("template", "ecerror") diff --git a/moto/elasticbeanstalk/exceptions.py b/moto/elasticbeanstalk/exceptions.py index 8c2cc2f5cf7b..fa67a9ea1a19 100644 --- a/moto/elasticbeanstalk/exceptions.py +++ b/moto/elasticbeanstalk/exceptions.py @@ -1,7 +1,5 @@ from typing import Any -from jinja2 import DictLoader, Environment - from moto.core.exceptions import RESTError EXCEPTION_RESPONSE = """ @@ -19,9 +17,7 @@ class ElasticBeanstalkException(RESTError): code = 400 extended_templates = {"ecerror": EXCEPTION_RESPONSE} - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, code: str, message: str, **kwargs: Any): kwargs.setdefault("template", "ecerror") diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py index 6a5d85d84c1c..baf3304123cf 100644 --- a/moto/s3/exceptions.py +++ b/moto/s3/exceptions.py @@ -1,7 +1,5 @@ from typing import TYPE_CHECKING, Any, Optional, Union -from jinja2 import DictLoader, Environment - from moto.core.exceptions import RESTError if TYPE_CHECKING: @@ -52,9 +50,7 @@ class S3ClientError(RESTError): "range_error": ERROR_WITH_RANGE, "storage_error": ERROR_WITH_STORAGE_CLASS, } - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") diff --git a/moto/s3control/exceptions.py b/moto/s3control/exceptions.py index fd5f1686dcbc..cd69cdcbdd0a 100644 --- a/moto/s3control/exceptions.py +++ b/moto/s3control/exceptions.py @@ -1,7 +1,5 @@ from typing import Any -from jinja2 import DictLoader, Environment - from moto.core.exceptions import RESTError ERROR_WITH_ACCESS_POINT_NAME = """{% extends 'wrapped_single_error' %} @@ -19,9 +17,7 @@ class S3ControlError(RESTError): "ap_not_found": ERROR_WITH_ACCESS_POINT_NAME, "apf_not_found": ERROR_WITH_ACCESS_POINT_POLICY, } - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") diff --git a/moto/sagemaker/exceptions.py b/moto/sagemaker/exceptions.py index b83f7d25064d..70266d8e72c2 100644 --- a/moto/sagemaker/exceptions.py +++ b/moto/sagemaker/exceptions.py @@ -1,7 +1,5 @@ from typing import Any -from jinja2 import DictLoader, Environment - from moto.core.exceptions import AWSError, JsonRESTError, RESTError ERROR_WITH_MODEL_NAME = """{% extends 'single_error' %} @@ -11,9 +9,7 @@ class SagemakerClientError(RESTError): extended_templates = {"model_error": ERROR_WITH_MODEL_NAME} - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") diff --git a/moto/sdb/exceptions.py b/moto/sdb/exceptions.py index 65c9221000c9..ae4efb66f8d7 100644 --- a/moto/sdb/exceptions.py +++ b/moto/sdb/exceptions.py @@ -1,8 +1,6 @@ """Exceptions raised by the sdb service.""" from typing import Any -from jinja2 import DictLoader, Environment - from moto.core.exceptions import RESTError SDB_ERROR = """ @@ -21,9 +19,7 @@ class InvalidParameterError(RESTError): code = 400 extended_templates = {"sdb_error": SDB_ERROR} - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, **kwargs: Any): kwargs.setdefault("template", "sdb_error") @@ -44,9 +40,7 @@ def __init__(self, domain_name: str): class UnknownDomainName(RESTError): code = 400 extended_templates = {"sdb_error": SDB_ERROR} - env = Environment( - loader=DictLoader(RESTError.extended_templates(extended_templates)) - ) + env = RESTError.extended_environment(extended_templates) def __init__(self, **kwargs: Any): kwargs.setdefault("template", "sdb_error") From 22cf83168e9f240b22a911108f460090bc22546d Mon Sep 17 00:00:00 2001 From: Joe Gordon Date: Tue, 19 Dec 2023 09:42:31 -0800 Subject: [PATCH 4/6] types --- moto/core/exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moto/core/exceptions.py b/moto/core/exceptions.py index c57003b78de2..44f0142927c6 100644 --- a/moto/core/exceptions.py +++ b/moto/core/exceptions.py @@ -96,7 +96,7 @@ def to_json(self) -> "JsonRESTError": return err @classmethod - def extended_environment(cls, extended_templates: Dict) -> Environment: + def extended_environment(cls, extended_templates: Dict[str, str]) -> Environment: # Can be simplified to cls.templates | extended_templates when we drop Python 3.8 support # https://docs.python.org/3/library/stdtypes.html#mapping-types-dict templates = dict(cls.templates.items() | extended_templates.items()) From 58a4e6a657608ce4f7d1db7a69ad80e7a34f518c Mon Sep 17 00:00:00 2001 From: Joe Gordon Date: Tue, 19 Dec 2023 12:22:52 -0800 Subject: [PATCH 5/6] Fix --- moto/core/exceptions.py | 2 +- moto/elasticbeanstalk/exceptions.py | 1 - moto/s3/exceptions.py | 10 ---------- moto/sagemaker/exceptions.py | 1 - moto/sdb/exceptions.py | 1 - 5 files changed, 1 insertion(+), 14 deletions(-) diff --git a/moto/core/exceptions.py b/moto/core/exceptions.py index 44f0142927c6..7be3b5979081 100644 --- a/moto/core/exceptions.py +++ b/moto/core/exceptions.py @@ -63,7 +63,7 @@ def __init__( self.error_type = error_type self.message = message - if template in self.templates.keys(): + if template in self.env.list_templates(): self.description: str = self.__class__.env.get_template(template).render( error_type=error_type, message=message, diff --git a/moto/elasticbeanstalk/exceptions.py b/moto/elasticbeanstalk/exceptions.py index fa67a9ea1a19..619adbaa1b5d 100644 --- a/moto/elasticbeanstalk/exceptions.py +++ b/moto/elasticbeanstalk/exceptions.py @@ -21,7 +21,6 @@ class ElasticBeanstalkException(RESTError): def __init__(self, code: str, message: str, **kwargs: Any): kwargs.setdefault("template", "ecerror") - self.templates["ecerror"] = EXCEPTION_RESPONSE super().__init__(code, message) diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py index baf3304123cf..337a9492ee24 100644 --- a/moto/s3/exceptions.py +++ b/moto/s3/exceptions.py @@ -54,7 +54,6 @@ class S3ClientError(RESTError): def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "single_error") - self.templates["bucket_error"] = ERROR_WITH_BUCKET_NAME super().__init__(*args, **kwargs) @@ -65,7 +64,6 @@ def __init__(self, message: str, name: str, value: str, *args: Any, **kwargs: An kwargs.setdefault("template", "argument_error") kwargs["name"] = name kwargs["value"] = value - self.templates["argument_error"] = ERROR_WITH_ARGUMENT super().__init__("InvalidArgument", message, *args, **kwargs) @@ -86,7 +84,6 @@ def __init__(self, msg: str): class BucketError(S3ClientError): def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "bucket_error") - self.templates["bucket_error"] = ERROR_WITH_BUCKET_NAME super().__init__(*args, **kwargs) @@ -95,7 +92,6 @@ class BucketAlreadyExists(BucketError): def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "bucket_error") - self.templates["bucket_error"] = ERROR_WITH_BUCKET_NAME super().__init__( "BucketAlreadyExists", ( @@ -122,7 +118,6 @@ class MissingKey(S3ClientError): def __init__(self, **kwargs: Any): kwargs.setdefault("template", "key_error") - self.templates["key_error"] = ERROR_WITH_KEY_NAME super().__init__("NoSuchKey", "The specified key does not exist.", **kwargs) @@ -140,7 +135,6 @@ def __init__(self, version_id: str, *args: Any, **kwargs: Any): kwargs.setdefault("template", "argument_error") kwargs["name"] = "versionId" kwargs["value"] = version_id - self.templates["argument_error"] = ERROR_WITH_ARGUMENT super().__init__( "InvalidArgument", "Invalid version id specified", *args, **kwargs ) @@ -447,7 +441,6 @@ class NoSuchUpload(S3ClientError): def __init__(self, upload_id: Union[int, str], *args: Any, **kwargs: Any): kwargs.setdefault("template", "error_uploadid") kwargs["upload_id"] = upload_id - self.templates["error_uploadid"] = ERROR_WITH_UPLOADID super().__init__( "NoSuchUpload", "The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.", @@ -461,7 +454,6 @@ class PreconditionFailed(S3ClientError): def __init__(self, failed_condition: str, **kwargs: Any): kwargs.setdefault("template", "condition_error") - self.templates["condition_error"] = ERROR_WITH_CONDITION_NAME super().__init__( "PreconditionFailed", "At least one of the pre-conditions you specified did not hold", @@ -475,7 +467,6 @@ class InvalidRange(S3ClientError): def __init__(self, range_requested: str, actual_size: str, **kwargs: Any): kwargs.setdefault("template", "range_error") - self.templates["range_error"] = ERROR_WITH_RANGE super().__init__( "InvalidRange", "The requested range is not satisfiable", @@ -499,7 +490,6 @@ class InvalidObjectState(BucketError): def __init__(self, storage_class: Optional[str], **kwargs: Any): kwargs.setdefault("template", "storage_error") - self.templates["storage_error"] = ERROR_WITH_STORAGE_CLASS super().__init__( error_type="InvalidObjectState", message="The operation is not valid for the object's storage class", diff --git a/moto/sagemaker/exceptions.py b/moto/sagemaker/exceptions.py index 70266d8e72c2..6e58c63c067c 100644 --- a/moto/sagemaker/exceptions.py +++ b/moto/sagemaker/exceptions.py @@ -19,7 +19,6 @@ def __init__(self, *args: Any, **kwargs: Any): class ModelError(RESTError): def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "model_error") - self.templates["model_error"] = ERROR_WITH_MODEL_NAME super().__init__(*args, **kwargs) diff --git a/moto/sdb/exceptions.py b/moto/sdb/exceptions.py index ae4efb66f8d7..07eb4e0990dc 100644 --- a/moto/sdb/exceptions.py +++ b/moto/sdb/exceptions.py @@ -23,7 +23,6 @@ class InvalidParameterError(RESTError): def __init__(self, **kwargs: Any): kwargs.setdefault("template", "sdb_error") - self.templates["sdb_error"] = SDB_ERROR kwargs["error_type"] = "InvalidParameterValue" super().__init__(**kwargs) From 35e8fefe1f3af145393f8d6b528b8017712b6a84 Mon Sep 17 00:00:00 2001 From: Joe Gordon Date: Tue, 19 Dec 2023 13:28:21 -0800 Subject: [PATCH 6/6] another one --- moto/sagemaker/exceptions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/moto/sagemaker/exceptions.py b/moto/sagemaker/exceptions.py index 6e58c63c067c..8f5750573488 100644 --- a/moto/sagemaker/exceptions.py +++ b/moto/sagemaker/exceptions.py @@ -17,6 +17,9 @@ def __init__(self, *args: Any, **kwargs: Any): class ModelError(RESTError): + extended_templates = {"model_error": ERROR_WITH_MODEL_NAME} + env = RESTError.extended_environment(extended_templates) + def __init__(self, *args: Any, **kwargs: Any): kwargs.setdefault("template", "model_error") super().__init__(*args, **kwargs)