diff --git a/docs/docs/configuration/index.rst b/docs/docs/configuration/index.rst index b98154f69..fc9f5d04f 100644 --- a/docs/docs/configuration/index.rst +++ b/docs/docs/configuration/index.rst @@ -12,6 +12,7 @@ Moto has a variety of ways to configure the mock behaviour. environment_variables recorder/index + prettify_responses state_transition/index state_transition/models diff --git a/docs/docs/configuration/prettify_responses.rst b/docs/docs/configuration/prettify_responses.rst new file mode 100644 index 000000000..e592a380a --- /dev/null +++ b/docs/docs/configuration/prettify_responses.rst @@ -0,0 +1,38 @@ +.. _prettify_responses_page: + +.. role:: raw-html(raw) + :format: html + +============================= +Prettify responses +============================= + +This option allows to prettify responses from moto. Pretty responses are more readable (eg. for debugging purposes). +It also makes moto better in mocking AWS as AWS returns prettified responses. + +Ugly output: + +.. sourcecode:: python + + 178936da-50ad-4d58-8871-22d9979e8658example1lt-d920e32b0cccd6adbexample-name + +Prettified output: + +.. sourcecode:: python + + + 178936da-50ad-4d58-8871-22d9979e8658example + + 1 + lt-d920e32b0cccd6adb + example-name + + + + +Configuration +################# + +As changing responses can interfere with some external tools, it is disabled by default. +If you want to enable it, use environment variable: +`MOTO_PRETTIFY_RESPONSES=True` \ No newline at end of file diff --git a/moto/core/responses.py b/moto/core/responses.py index ac47413a2..432d50b96 100644 --- a/moto/core/responses.py +++ b/moto/core/responses.py @@ -18,6 +18,8 @@ from jinja2 import Environment, DictLoader from typing import Dict, List, Union, Any, Optional from urllib.parse import parse_qs, parse_qsl, urlparse from werkzeug.exceptions import HTTPException +from xml.dom.minidom import parseString as parseXML + log = logging.getLogger(__name__) @@ -104,10 +106,15 @@ class _TemplateEnvironmentMixin(object): def response_template(self, source): template_id = self._make_template_id(source) if not self.contains_template(template_id): - collapsed = re.sub( - self.RIGHT_PATTERN, ">", re.sub(self.LEFT_PATTERN, "<", source) - ) - self.environment.loader.update({template_id: collapsed}) + if settings.PRETTIFY_RESPONSES: + # pretty xml + xml = parseXML(source).toprettyxml() + else: + # collapsed xml + xml = re.sub( + self.RIGHT_PATTERN, ">", re.sub(self.LEFT_PATTERN, "<", source) + ) + self.environment.loader.update({template_id: xml}) return self.environment.get_template(template_id) diff --git a/moto/settings.py b/moto/settings.py index 13e1b2a17..65ceaeb4d 100644 --- a/moto/settings.py +++ b/moto/settings.py @@ -29,6 +29,9 @@ ENABLE_KEYPAIR_VALIDATION = bool( ENABLE_AMI_VALIDATION = bool(os.environ.get("MOTO_ENABLE_AMI_VALIDATION", False)) +PRETTIFY_RESPONSES = bool(os.environ.get("MOTO_PRETTIFY_RESPONSES", False)) + + def get_sf_execution_history_type(): """ Determines which execution history events `get_execution_history` returns diff --git a/tests/test_core/test_responses.py b/tests/test_core/test_responses.py index 5f4208486..728f6012d 100644 --- a/tests/test_core/test_responses.py +++ b/tests/test_core/test_responses.py @@ -1,3 +1,4 @@ +from unittest import SkipTest, mock import sure # noqa # pylint: disable=unused-import from collections import OrderedDict @@ -6,6 +7,7 @@ from botocore.awsrequest import AWSPreparedRequest from moto.core.responses import AWSServiceSpec, BaseResponse from moto.core.responses import flatten_json_request_body +from moto import settings def test_flatten_json_request_body(): @@ -205,3 +207,21 @@ def test_response_environment_preserved_by_type(): assert resp_a_new_instance.contains_template( BaseResponse._make_template_id(source_2) ) + + +@mock.patch( + "moto.core.responses.settings.PRETTIFY_RESPONSES", + new_callable=mock.PropertyMock(return_value=True), +) +def test_jinja_render_prettify(m_env_var): + if settings.TEST_SERVER_MODE: + raise SkipTest( + "It is not possible to set the environment variable in server mode" + ) + response = BaseResponse() + TEMPLATE = """Test text""" + expected_output = '\n\n\tTest text\n' + template = response.response_template(TEMPLATE) + xml_string = template.render() + assert xml_string == expected_output + assert m_env_var