We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
V2 Custom Expectation Custom Rendering No Longer Works
**Describe the bug**
V2 custom expectation custom rendering (as documented [here](https://docs.greatexpectations.io/en/latest/reference/spare_parts/data_docs_reference.html#customizing-data-docs)) no longer works.

**To Reproduce**
Steps to reproduce the behavior:
1. `git clone --branch jdimatteo/reproduce-custom-expectation-rendering-bug git@github.com:jdimatteo/great_expectations.git && cd great_expectations/tests/integration/docusaurus/connecting_to_your_data/database/`
2. `python3.9 -m venv venv0.13.25 && source venv0.13.25/bin/activate`
3. `pip install -r requirements-0.13.25.txt`
4. `python sqlite_python_example_with_v2_api.py`

This should run without error as it does with GE version 0.12.7 (see details below), however instead fails as shown in this AssertionError:

```
Traceback (most recent call last):
  File "/home/jdimatteo/dev/great_expectations_fork_1/tests/integration/docusaurus/connecting_to_your_data/database/sqlite_python_example_with_v2_api.py", line 161, in <module>
    main()
  File "/home/jdimatteo/dev/great_expectations_fork_1/tests/integration/docusaurus/connecting_to_your_data/database/sqlite_python_example_with_v2_api.py", line 158, in main
    assert_custom_rendering_present_in_html()
  File "/home/jdimatteo/dev/great_expectations_fork_1/tests/integration/docusaurus/connecting_to_your_data/database/sqlite_python_example_with_v2_api.py", line 141, in assert_custom_rendering_present_in_html
    assert "**{" not in html_file_contents
AssertionError
```

This `AssertionError` corresponds to the missing custom rendering as shown here:

![image](https://user-images.githubusercontent.com/3752732/128114821-208db9d3-741b-46eb-bbd2-b4973bc62095.png)

**Expected behavior**

Custom rendering should work as it did in prior GE version 0.12.7:

1. `git clone --branch jdimatteo/reproduce-custom-expectation-rendering-bug git@github.com:jdimatteo/great_expectations.git && cd great_expectations/tests/integration/docusaurus/connecting_to_your_data/database/`
2. `python3.9 -m venv venv0.12.7 && source venv0.12.7/bin/activate`
3. `pip install -r requirements-0.12.7.txt`
4. `python sqlite_python_example_with_v2_api.py`

This runs without error and produces expected custom rendering:

![image](https://user-images.githubusercontent.com/3752732/128114904-f6118a7d-931a-4bf9-aa3c-ad247b3c0f9a.png)

**Environment (please complete the following information):**
 - Operating System: Linux
 - Great Expectations Version: 0.13.25

**Additional context**

I understand that the V2 API is going to be deprecated at some point, however it isn't deprecated yet and the V3 API isn't ready for all use cases because it is documented as experimental [here](https://docs.greatexpectations.io/en/latest/guides/how_to_guides/migrating_versions.html) and there are several bugs preventing usage that might not be fixed for several weeks (e.g. https://github.com/great-expectations/great_expectations/issues/3095). Using an old version of Great Expectations is also not an option, because doing so requires using older versions of other libraries as well such as urllib3 with security vulnerabilities including https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33503.

See also discussion at https://greatexpectationstalk.slack.com/archives/CUTCNHN82/p1628046306055600.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `great_expectations/render/renderer/content_block/validation_results_table_content_block.py`
Content:
```
1 import logging
2 import traceback
3 from copy import deepcopy
4 
5 from great_expectations.expectations.core.expect_column_kl_divergence_to_be_less_than import (
6     ExpectColumnKlDivergenceToBeLessThan,
7 )
8 from great_expectations.expectations.registry import get_renderer_impl
9 from great_expectations.render.renderer.content_block.expectation_string import (
10     ExpectationStringRenderer,
11 )
12 from great_expectations.render.types import (
13     CollapseContent,
14     RenderedContentBlockContainer,
15     RenderedStringTemplateContent,
16     RenderedTableContent,
17 )
18 from great_expectations.render.util import num_to_str
19 
20 logger = logging.getLogger(__name__)
21 
22 
23 class ValidationResultsTableContentBlockRenderer(ExpectationStringRenderer):
24     _content_block_type = "table"
25     _rendered_component_type = RenderedTableContent
26     _rendered_component_default_init_kwargs = {
27         "table_options": {"search": True, "icon-size": "sm"}
28     }
29 
30     _default_element_styling = {
31         "default": {"classes": ["badge", "badge-secondary"]},
32         "params": {"column": {"classes": ["badge", "badge-primary"]}},
33     }
34 
35     _default_content_block_styling = {
36         "body": {
37             "classes": ["table"],
38         },
39         "classes": ["ml-2", "mr-2", "mt-0", "mb-0", "table-responsive"],
40     }
41 
42     @classmethod
43     def _process_content_block(cls, content_block, has_failed_evr):
44         super()._process_content_block(content_block, has_failed_evr)
45         content_block.header_row = ["Status", "Expectation", "Observed Value"]
46         content_block.header_row_options = {"Status": {"sortable": True}}
47 
48         if has_failed_evr is False:
49             styling = deepcopy(content_block.styling) if content_block.styling else {}
50             if styling.get("classes"):
51                 styling["classes"].append(
52                     "hide-succeeded-validations-column-section-target-child"
53                 )
54             else:
55                 styling["classes"] = [
56                     "hide-succeeded-validations-column-section-target-child"
57                 ]
58 
59             content_block.styling = styling
60 
61     @classmethod
62     def _get_content_block_fn(cls, expectation_type):
63         expectation_string_fn = get_renderer_impl(
64             object_name=expectation_type, renderer_type="renderer.prescriptive"
65         )
66         expectation_string_fn = (
67             expectation_string_fn[1] if expectation_string_fn else None
68         )
69         if expectation_string_fn is None:
70             expectation_string_fn = getattr(cls, "_missing_content_block_fn")
71 
72         # This function wraps expect_* methods from ExpectationStringRenderer to generate table classes
73         def row_generator_fn(
74             configuration=None,
75             result=None,
76             language=None,
77             runtime_configuration=None,
78             **kwargs,
79         ):
80             eval_param_value_dict = kwargs.get("evaluation_parameters", None)
81             # loading into evaluation parameters to be passed onto prescriptive renderer
82             if eval_param_value_dict is not None:
83                 runtime_configuration["evaluation_parameters"] = eval_param_value_dict
84 
85             expectation = result.expectation_config
86             expectation_string_cell = expectation_string_fn(
87                 configuration=expectation, runtime_configuration=runtime_configuration
88             )
89 
90             status_icon_renderer = get_renderer_impl(
91                 object_name=expectation_type,
92                 renderer_type="renderer.diagnostic.status_icon",
93             )
94             status_cell = (
95                 [status_icon_renderer[1](result=result)]
96                 if status_icon_renderer
97                 else [getattr(cls, "_diagnostic_status_icon_renderer")(result=result)]
98             )
99             unexpected_statement = []
100             unexpected_table = None
101             observed_value = ["--"]
102 
103             data_docs_exception_message = f"""\
104 An unexpected Exception occurred during data docs rendering.  Because of this error, certain parts of data docs will \
105 not be rendered properly and/or may not appear altogether.  Please use the trace, included in this message, to \
106 diagnose and repair the underlying issue.  Detailed information follows:
107             """
108             try:
109                 unexpected_statement_renderer = get_renderer_impl(
110                     object_name=expectation_type,
111                     renderer_type="renderer.diagnostic.unexpected_statement",
112                 )
113                 unexpected_statement = (
114                     unexpected_statement_renderer[1](result=result)
115                     if unexpected_statement_renderer
116                     else []
117                 )
118             except Exception as e:
119                 exception_traceback = traceback.format_exc()
120                 exception_message = (
121                     data_docs_exception_message
122                     + f'{type(e).__name__}: "{str(e)}".  Traceback: "{exception_traceback}".'
123                 )
124                 logger.error(exception_message)
125             try:
126                 unexpected_table_renderer = get_renderer_impl(
127                     object_name=expectation_type,
128                     renderer_type="renderer.diagnostic.unexpected_table",
129                 )
130                 unexpected_table = (
131                     unexpected_table_renderer[1](result=result)
132                     if unexpected_table_renderer
133                     else None
134                 )
135             except Exception as e:
136                 exception_traceback = traceback.format_exc()
137                 exception_message = (
138                     data_docs_exception_message
139                     + f'{type(e).__name__}: "{str(e)}".  Traceback: "{exception_traceback}".'
140                 )
141                 logger.error(exception_message)
142             try:
143                 observed_value_renderer = get_renderer_impl(
144                     object_name=expectation_type,
145                     renderer_type="renderer.diagnostic.observed_value",
146                 )
147                 observed_value = [
148                     observed_value_renderer[1](result=result)
149                     if observed_value_renderer
150                     else "--"
151                 ]
152             except Exception as e:
153                 exception_traceback = traceback.format_exc()
154                 exception_message = (
155                     data_docs_exception_message
156                     + f'{type(e).__name__}: "{str(e)}".  Traceback: "{exception_traceback}".'
157                 )
158                 logger.error(exception_message)
159 
160             # If the expectation has some unexpected values...:
161             if unexpected_statement:
162                 expectation_string_cell += unexpected_statement
163             if unexpected_table:
164                 expectation_string_cell.append(unexpected_table)
165             if len(expectation_string_cell) > 1:
166                 return [status_cell + [expectation_string_cell] + observed_value]
167             else:
168                 return [status_cell + expectation_string_cell + observed_value]
169 
170         return row_generator_fn
171
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/great_expectations/render/renderer/content_block/validation_results_table_content_block.py b/great_expectations/render/renderer/content_block/validation_results_table_content_block.py
--- a/great_expectations/render/renderer/content_block/validation_results_table_content_block.py
+++ b/great_expectations/render/renderer/content_block/validation_results_table_content_block.py
@@ -1,7 +1,9 @@
 import logging
 import traceback
+import warnings
 from copy import deepcopy
 
+from great_expectations.core.expectation_configuration import ExpectationConfiguration
 from great_expectations.expectations.core.expect_column_kl_divergence_to_be_less_than import (
     ExpectColumnKlDivergenceToBeLessThan,
 )
@@ -66,6 +68,10 @@
         expectation_string_fn = (
             expectation_string_fn[1] if expectation_string_fn else None
         )
+        if expectation_string_fn is None:
+            expectation_string_fn = cls._get_legacy_v2_api_style_expectation_string_fn(
+                expectation_type
+            )
         if expectation_string_fn is None:
             expectation_string_fn = getattr(cls, "_missing_content_block_fn")
 
@@ -147,7 +153,12 @@
                 observed_value = [
                     observed_value_renderer[1](result=result)
                     if observed_value_renderer
-                    else "--"
+                    else (
+                        cls._get_legacy_v2_api_observed_value(
+                            expectation_string_fn, result
+                        )
+                        or "--"
+                    )
                 ]
             except Exception as e:
                 exception_traceback = traceback.format_exc()
@@ -168,3 +179,46 @@
                 return [status_cell + expectation_string_cell + observed_value]
 
         return row_generator_fn
+
+    @classmethod
+    def _get_legacy_v2_api_style_expectation_string_fn(cls, expectation_type):
+        legacy_expectation_string_fn = getattr(cls, expectation_type, None)
+        if legacy_expectation_string_fn is None:
+            # With the V2 API, expectation rendering was implemented by defining a method with the same name as the expectation.
+            # If no legacy rendering is present, return None.
+            return None
+
+        warnings.warn(
+            "V2 API style custom rendering is deprecated and is not fully supported anymore; please switch to V3 API and associated rendering style",
+            DeprecationWarning,
+        )
+
+        def expectation_string_fn_with_legacy_translation(
+            configuration: ExpectationConfiguration, runtime_configuration: dict
+        ):
+            if runtime_configuration is None:
+                runtime_configuration = {}
+
+            # With the V2 API, the expectation string function had a different signature; the below translates from the new signature to the legacy signature.
+            return legacy_expectation_string_fn(
+                expectation=configuration,
+                styling=runtime_configuration.get("styling", None),
+                include_column_name=runtime_configuration.get(
+                    "include_column_name", True
+                ),
+            )
+
+        return expectation_string_fn_with_legacy_translation
+
+    @staticmethod
+    def _get_legacy_v2_api_observed_value(expectation_string_fn, result):
+        if (
+            expectation_string_fn.__name__
+            != "expectation_string_fn_with_legacy_translation"
+        ):
+            # If legacy V2 API style rendering is used, "expectation_string_fn" will be the method defined in the above "_get_legacy_v2_api_style_expectation_string_fn".
+            # If this isn't the case, return None, so we don't do any legacy logic.
+            return None
+
+        # With V2 API style rendering, the result had an "observed_value" entry that could be rendered.
+        return result["result"].get("observed_value")

{"golden_diff": "diff --git a/great_expectations/render/renderer/content_block/validation_results_table_content_block.py b/great_expectations/render/renderer/content_block/validation_results_table_content_block.py\n--- a/great_expectations/render/renderer/content_block/validation_results_table_content_block.py\n+++ b/great_expectations/render/renderer/content_block/validation_results_table_content_block.py\n@@ -1,7 +1,9 @@\n import logging\n import traceback\n+import warnings\n from copy import deepcopy\n \n+from great_expectations.core.expectation_configuration import ExpectationConfiguration\n from great_expectations.expectations.core.expect_column_kl_divergence_to_be_less_than import (\n     ExpectColumnKlDivergenceToBeLessThan,\n )\n@@ -66,6 +68,10 @@\n         expectation_string_fn = (\n             expectation_string_fn[1] if expectation_string_fn else None\n         )\n+        if expectation_string_fn is None:\n+            expectation_string_fn = cls._get_legacy_v2_api_style_expectation_string_fn(\n+                expectation_type\n+            )\n         if expectation_string_fn is None:\n             expectation_string_fn = getattr(cls, \"_missing_content_block_fn\")\n \n@@ -147,7 +153,12 @@\n                 observed_value = [\n                     observed_value_renderer[1](result=result)\n                     if observed_value_renderer\n-                    else \"--\"\n+                    else (\n+                        cls._get_legacy_v2_api_observed_value(\n+                            expectation_string_fn, result\n+                        )\n+                        or \"--\"\n+                    )\n                 ]\n             except Exception as e:\n                 exception_traceback = traceback.format_exc()\n@@ -168,3 +179,46 @@\n                 return [status_cell + expectation_string_cell + observed_value]\n \n         return row_generator_fn\n+\n+    @classmethod\n+    def _get_legacy_v2_api_style_expectation_string_fn(cls, expectation_type):\n+        legacy_expectation_string_fn = getattr(cls, expectation_type, None)\n+        if legacy_expectation_string_fn is None:\n+            # With the V2 API, expectation rendering was implemented by defining a method with the same name as the expectation.\n+            # If no legacy rendering is present, return None.\n+            return None\n+\n+        warnings.warn(\n+            \"V2 API style custom rendering is deprecated and is not fully supported anymore; please switch to V3 API and associated rendering style\",\n+            DeprecationWarning,\n+        )\n+\n+        def expectation_string_fn_with_legacy_translation(\n+            configuration: ExpectationConfiguration, runtime_configuration: dict\n+        ):\n+            if runtime_configuration is None:\n+                runtime_configuration = {}\n+\n+            # With the V2 API, the expectation string function had a different signature; the below translates from the new signature to the legacy signature.\n+            return legacy_expectation_string_fn(\n+                expectation=configuration,\n+                styling=runtime_configuration.get(\"styling\", None),\n+                include_column_name=runtime_configuration.get(\n+                    \"include_column_name\", True\n+                ),\n+            )\n+\n+        return expectation_string_fn_with_legacy_translation\n+\n+    @staticmethod\n+    def _get_legacy_v2_api_observed_value(expectation_string_fn, result):\n+        if (\n+            expectation_string_fn.__name__\n+            != \"expectation_string_fn_with_legacy_translation\"\n+        ):\n+            # If legacy V2 API style rendering is used, \"expectation_string_fn\" will be the method defined in the above \"_get_legacy_v2_api_style_expectation_string_fn\".\n+            # If this isn't the case, return None, so we don't do any legacy logic.\n+            return None\n+\n+        # With V2 API style rendering, the result had an \"observed_value\" entry that could be rendered.\n+        return result[\"result\"].get(\"observed_value\")\n", "issue": "V2 Custom Expectation Custom Rendering No Longer Works\n**Describe the bug**\r\nV2 custom expectation custom rendering (as documented [here](https://docs.greatexpectations.io/en/latest/reference/spare_parts/data_docs_reference.html#customizing-data-docs)) no longer works.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. `git clone --branch jdimatteo/reproduce-custom-expectation-rendering-bug git@github.com:jdimatteo/great_expectations.git && cd great_expectations/tests/integration/docusaurus/connecting_to_your_data/database/`\r\n2. `python3.9 -m venv venv0.13.25 && source venv0.13.25/bin/activate`\r\n3. `pip install -r requirements-0.13.25.txt`\r\n4. `python sqlite_python_example_with_v2_api.py`\r\n\r\nThis should run without error as it does with GE version 0.12.7 (see details below), however instead fails as shown in this AssertionError:\r\n\r\n```\r\nTraceback (most recent call last):\r\n  File \"/home/jdimatteo/dev/great_expectations_fork_1/tests/integration/docusaurus/connecting_to_your_data/database/sqlite_python_example_with_v2_api.py\", line 161, in <module>\r\n    main()\r\n  File \"/home/jdimatteo/dev/great_expectations_fork_1/tests/integration/docusaurus/connecting_to_your_data/database/sqlite_python_example_with_v2_api.py\", line 158, in main\r\n    assert_custom_rendering_present_in_html()\r\n  File \"/home/jdimatteo/dev/great_expectations_fork_1/tests/integration/docusaurus/connecting_to_your_data/database/sqlite_python_example_with_v2_api.py\", line 141, in assert_custom_rendering_present_in_html\r\n    assert \"**{\" not in html_file_contents\r\nAssertionError\r\n```\r\n\r\nThis `AssertionError` corresponds to the missing custom rendering as shown here:\r\n\r\n![image](https://user-images.githubusercontent.com/3752732/128114821-208db9d3-741b-46eb-bbd2-b4973bc62095.png)\r\n\r\n**Expected behavior**\r\n\r\nCustom rendering should work as it did in prior GE version 0.12.7:\r\n\r\n1. `git clone --branch jdimatteo/reproduce-custom-expectation-rendering-bug git@github.com:jdimatteo/great_expectations.git && cd great_expectations/tests/integration/docusaurus/connecting_to_your_data/database/`\r\n2. `python3.9 -m venv venv0.12.7 && source venv0.12.7/bin/activate`\r\n3. `pip install -r requirements-0.12.7.txt`\r\n4. `python sqlite_python_example_with_v2_api.py`\r\n\r\nThis runs without error and produces expected custom rendering:\r\n\r\n![image](https://user-images.githubusercontent.com/3752732/128114904-f6118a7d-931a-4bf9-aa3c-ad247b3c0f9a.png)\r\n\r\n**Environment (please complete the following information):**\r\n - Operating System: Linux\r\n - Great Expectations Version: 0.13.25\r\n\r\n**Additional context**\r\n\r\nI understand that the V2 API is going to be deprecated at some point, however it isn't deprecated yet and the V3 API isn't ready for all use cases because it is documented as experimental [here](https://docs.greatexpectations.io/en/latest/guides/how_to_guides/migrating_versions.html) and there are several bugs preventing usage that might not be fixed for several weeks (e.g. https://github.com/great-expectations/great_expectations/issues/3095). Using an old version of Great Expectations is also not an option, because doing so requires using older versions of other libraries as well such as urllib3 with security vulnerabilities including https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33503.\r\n\r\nSee also discussion at https://greatexpectationstalk.slack.com/archives/CUTCNHN82/p1628046306055600.\n", "before_files": [{"content": "import logging\nimport traceback\nfrom copy import deepcopy\n\nfrom great_expectations.expectations.core.expect_column_kl_divergence_to_be_less_than import (\n    ExpectColumnKlDivergenceToBeLessThan,\n)\nfrom great_expectations.expectations.registry import get_renderer_impl\nfrom great_expectations.render.renderer.content_block.expectation_string import (\n    ExpectationStringRenderer,\n)\nfrom great_expectations.render.types import (\n    CollapseContent,\n    RenderedContentBlockContainer,\n    RenderedStringTemplateContent,\n    RenderedTableContent,\n)\nfrom great_expectations.render.util import num_to_str\n\nlogger = logging.getLogger(__name__)\n\n\nclass ValidationResultsTableContentBlockRenderer(ExpectationStringRenderer):\n    _content_block_type = \"table\"\n    _rendered_component_type = RenderedTableContent\n    _rendered_component_default_init_kwargs = {\n        \"table_options\": {\"search\": True, \"icon-size\": \"sm\"}\n    }\n\n    _default_element_styling = {\n        \"default\": {\"classes\": [\"badge\", \"badge-secondary\"]},\n        \"params\": {\"column\": {\"classes\": [\"badge\", \"badge-primary\"]}},\n    }\n\n    _default_content_block_styling = {\n        \"body\": {\n            \"classes\": [\"table\"],\n        },\n        \"classes\": [\"ml-2\", \"mr-2\", \"mt-0\", \"mb-0\", \"table-responsive\"],\n    }\n\n    @classmethod\n    def _process_content_block(cls, content_block, has_failed_evr):\n        super()._process_content_block(content_block, has_failed_evr)\n        content_block.header_row = [\"Status\", \"Expectation\", \"Observed Value\"]\n        content_block.header_row_options = {\"Status\": {\"sortable\": True}}\n\n        if has_failed_evr is False:\n            styling = deepcopy(content_block.styling) if content_block.styling else {}\n            if styling.get(\"classes\"):\n                styling[\"classes\"].append(\n                    \"hide-succeeded-validations-column-section-target-child\"\n                )\n            else:\n                styling[\"classes\"] = [\n                    \"hide-succeeded-validations-column-section-target-child\"\n                ]\n\n            content_block.styling = styling\n\n    @classmethod\n    def _get_content_block_fn(cls, expectation_type):\n        expectation_string_fn = get_renderer_impl(\n            object_name=expectation_type, renderer_type=\"renderer.prescriptive\"\n        )\n        expectation_string_fn = (\n            expectation_string_fn[1] if expectation_string_fn else None\n        )\n        if expectation_string_fn is None:\n            expectation_string_fn = getattr(cls, \"_missing_content_block_fn\")\n\n        # This function wraps expect_* methods from ExpectationStringRenderer to generate table classes\n        def row_generator_fn(\n            configuration=None,\n            result=None,\n            language=None,\n            runtime_configuration=None,\n            **kwargs,\n        ):\n            eval_param_value_dict = kwargs.get(\"evaluation_parameters\", None)\n            # loading into evaluation parameters to be passed onto prescriptive renderer\n            if eval_param_value_dict is not None:\n                runtime_configuration[\"evaluation_parameters\"] = eval_param_value_dict\n\n            expectation = result.expectation_config\n            expectation_string_cell = expectation_string_fn(\n                configuration=expectation, runtime_configuration=runtime_configuration\n            )\n\n            status_icon_renderer = get_renderer_impl(\n                object_name=expectation_type,\n                renderer_type=\"renderer.diagnostic.status_icon\",\n            )\n            status_cell = (\n                [status_icon_renderer[1](result=result)]\n                if status_icon_renderer\n                else [getattr(cls, \"_diagnostic_status_icon_renderer\")(result=result)]\n            )\n            unexpected_statement = []\n            unexpected_table = None\n            observed_value = [\"--\"]\n\n            data_docs_exception_message = f\"\"\"\\\nAn unexpected Exception occurred during data docs rendering.  Because of this error, certain parts of data docs will \\\nnot be rendered properly and/or may not appear altogether.  Please use the trace, included in this message, to \\\ndiagnose and repair the underlying issue.  Detailed information follows:\n            \"\"\"\n            try:\n                unexpected_statement_renderer = get_renderer_impl(\n                    object_name=expectation_type,\n                    renderer_type=\"renderer.diagnostic.unexpected_statement\",\n                )\n                unexpected_statement = (\n                    unexpected_statement_renderer[1](result=result)\n                    if unexpected_statement_renderer\n                    else []\n                )\n            except Exception as e:\n                exception_traceback = traceback.format_exc()\n                exception_message = (\n                    data_docs_exception_message\n                    + f'{type(e).__name__}: \"{str(e)}\".  Traceback: \"{exception_traceback}\".'\n                )\n                logger.error(exception_message)\n            try:\n                unexpected_table_renderer = get_renderer_impl(\n                    object_name=expectation_type,\n                    renderer_type=\"renderer.diagnostic.unexpected_table\",\n                )\n                unexpected_table = (\n                    unexpected_table_renderer[1](result=result)\n                    if unexpected_table_renderer\n                    else None\n                )\n            except Exception as e:\n                exception_traceback = traceback.format_exc()\n                exception_message = (\n                    data_docs_exception_message\n                    + f'{type(e).__name__}: \"{str(e)}\".  Traceback: \"{exception_traceback}\".'\n                )\n                logger.error(exception_message)\n            try:\n                observed_value_renderer = get_renderer_impl(\n                    object_name=expectation_type,\n                    renderer_type=\"renderer.diagnostic.observed_value\",\n                )\n                observed_value = [\n                    observed_value_renderer[1](result=result)\n                    if observed_value_renderer\n                    else \"--\"\n                ]\n            except Exception as e:\n                exception_traceback = traceback.format_exc()\n                exception_message = (\n                    data_docs_exception_message\n                    + f'{type(e).__name__}: \"{str(e)}\".  Traceback: \"{exception_traceback}\".'\n                )\n                logger.error(exception_message)\n\n            # If the expectation has some unexpected values...:\n            if unexpected_statement:\n                expectation_string_cell += unexpected_statement\n            if unexpected_table:\n                expectation_string_cell.append(unexpected_table)\n            if len(expectation_string_cell) > 1:\n                return [status_cell + [expectation_string_cell] + observed_value]\n            else:\n                return [status_cell + expectation_string_cell + observed_value]\n\n        return row_generator_fn\n", "path": "great_expectations/render/renderer/content_block/validation_results_table_content_block.py"}], "after_files": [{"content": "import logging\nimport traceback\nimport warnings\nfrom copy import deepcopy\n\nfrom great_expectations.core.expectation_configuration import ExpectationConfiguration\nfrom great_expectations.expectations.core.expect_column_kl_divergence_to_be_less_than import (\n    ExpectColumnKlDivergenceToBeLessThan,\n)\nfrom great_expectations.expectations.registry import get_renderer_impl\nfrom great_expectations.render.renderer.content_block.expectation_string import (\n    ExpectationStringRenderer,\n)\nfrom great_expectations.render.types import (\n    CollapseContent,\n    RenderedContentBlockContainer,\n    RenderedStringTemplateContent,\n    RenderedTableContent,\n)\nfrom great_expectations.render.util import num_to_str\n\nlogger = logging.getLogger(__name__)\n\n\nclass ValidationResultsTableContentBlockRenderer(ExpectationStringRenderer):\n    _content_block_type = \"table\"\n    _rendered_component_type = RenderedTableContent\n    _rendered_component_default_init_kwargs = {\n        \"table_options\": {\"search\": True, \"icon-size\": \"sm\"}\n    }\n\n    _default_element_styling = {\n        \"default\": {\"classes\": [\"badge\", \"badge-secondary\"]},\n        \"params\": {\"column\": {\"classes\": [\"badge\", \"badge-primary\"]}},\n    }\n\n    _default_content_block_styling = {\n        \"body\": {\n            \"classes\": [\"table\"],\n        },\n        \"classes\": [\"ml-2\", \"mr-2\", \"mt-0\", \"mb-0\", \"table-responsive\"],\n    }\n\n    @classmethod\n    def _process_content_block(cls, content_block, has_failed_evr):\n        super()._process_content_block(content_block, has_failed_evr)\n        content_block.header_row = [\"Status\", \"Expectation\", \"Observed Value\"]\n        content_block.header_row_options = {\"Status\": {\"sortable\": True}}\n\n        if has_failed_evr is False:\n            styling = deepcopy(content_block.styling) if content_block.styling else {}\n            if styling.get(\"classes\"):\n                styling[\"classes\"].append(\n                    \"hide-succeeded-validations-column-section-target-child\"\n                )\n            else:\n                styling[\"classes\"] = [\n                    \"hide-succeeded-validations-column-section-target-child\"\n                ]\n\n            content_block.styling = styling\n\n    @classmethod\n    def _get_content_block_fn(cls, expectation_type):\n        expectation_string_fn = get_renderer_impl(\n            object_name=expectation_type, renderer_type=\"renderer.prescriptive\"\n        )\n        expectation_string_fn = (\n            expectation_string_fn[1] if expectation_string_fn else None\n        )\n        if expectation_string_fn is None:\n            expectation_string_fn = cls._get_legacy_v2_api_style_expectation_string_fn(\n                expectation_type\n            )\n        if expectation_string_fn is None:\n            expectation_string_fn = getattr(cls, \"_missing_content_block_fn\")\n\n        # This function wraps expect_* methods from ExpectationStringRenderer to generate table classes\n        def row_generator_fn(\n            configuration=None,\n            result=None,\n            language=None,\n            runtime_configuration=None,\n            **kwargs,\n        ):\n            eval_param_value_dict = kwargs.get(\"evaluation_parameters\", None)\n            # loading into evaluation parameters to be passed onto prescriptive renderer\n            if eval_param_value_dict is not None:\n                runtime_configuration[\"evaluation_parameters\"] = eval_param_value_dict\n\n            expectation = result.expectation_config\n            expectation_string_cell = expectation_string_fn(\n                configuration=expectation, runtime_configuration=runtime_configuration\n            )\n\n            status_icon_renderer = get_renderer_impl(\n                object_name=expectation_type,\n                renderer_type=\"renderer.diagnostic.status_icon\",\n            )\n            status_cell = (\n                [status_icon_renderer[1](result=result)]\n                if status_icon_renderer\n                else [getattr(cls, \"_diagnostic_status_icon_renderer\")(result=result)]\n            )\n            unexpected_statement = []\n            unexpected_table = None\n            observed_value = [\"--\"]\n\n            data_docs_exception_message = f\"\"\"\\\nAn unexpected Exception occurred during data docs rendering.  Because of this error, certain parts of data docs will \\\nnot be rendered properly and/or may not appear altogether.  Please use the trace, included in this message, to \\\ndiagnose and repair the underlying issue.  Detailed information follows:\n            \"\"\"\n            try:\n                unexpected_statement_renderer = get_renderer_impl(\n                    object_name=expectation_type,\n                    renderer_type=\"renderer.diagnostic.unexpected_statement\",\n                )\n                unexpected_statement = (\n                    unexpected_statement_renderer[1](result=result)\n                    if unexpected_statement_renderer\n                    else []\n                )\n            except Exception as e:\n                exception_traceback = traceback.format_exc()\n                exception_message = (\n                    data_docs_exception_message\n                    + f'{type(e).__name__}: \"{str(e)}\".  Traceback: \"{exception_traceback}\".'\n                )\n                logger.error(exception_message)\n            try:\n                unexpected_table_renderer = get_renderer_impl(\n                    object_name=expectation_type,\n                    renderer_type=\"renderer.diagnostic.unexpected_table\",\n                )\n                unexpected_table = (\n                    unexpected_table_renderer[1](result=result)\n                    if unexpected_table_renderer\n                    else None\n                )\n            except Exception as e:\n                exception_traceback = traceback.format_exc()\n                exception_message = (\n                    data_docs_exception_message\n                    + f'{type(e).__name__}: \"{str(e)}\".  Traceback: \"{exception_traceback}\".'\n                )\n                logger.error(exception_message)\n            try:\n                observed_value_renderer = get_renderer_impl(\n                    object_name=expectation_type,\n                    renderer_type=\"renderer.diagnostic.observed_value\",\n                )\n                observed_value = [\n                    observed_value_renderer[1](result=result)\n                    if observed_value_renderer\n                    else (\n                        cls._get_legacy_v2_api_observed_value(\n                            expectation_string_fn, result\n                        )\n                        or \"--\"\n                    )\n                ]\n            except Exception as e:\n                exception_traceback = traceback.format_exc()\n                exception_message = (\n                    data_docs_exception_message\n                    + f'{type(e).__name__}: \"{str(e)}\".  Traceback: \"{exception_traceback}\".'\n                )\n                logger.error(exception_message)\n\n            # If the expectation has some unexpected values...:\n            if unexpected_statement:\n                expectation_string_cell += unexpected_statement\n            if unexpected_table:\n                expectation_string_cell.append(unexpected_table)\n            if len(expectation_string_cell) > 1:\n                return [status_cell + [expectation_string_cell] + observed_value]\n            else:\n                return [status_cell + expectation_string_cell + observed_value]\n\n        return row_generator_fn\n\n    @classmethod\n    def _get_legacy_v2_api_style_expectation_string_fn(cls, expectation_type):\n        legacy_expectation_string_fn = getattr(cls, expectation_type, None)\n        if legacy_expectation_string_fn is None:\n            # With the V2 API, expectation rendering was implemented by defining a method with the same name as the expectation.\n            # If no legacy rendering is present, return None.\n            return None\n\n        warnings.warn(\n            \"V2 API style custom rendering is deprecated and is not fully supported anymore; please switch to V3 API and associated rendering style\",\n            DeprecationWarning,\n        )\n\n        def expectation_string_fn_with_legacy_translation(\n            configuration: ExpectationConfiguration, runtime_configuration: dict\n        ):\n            if runtime_configuration is None:\n                runtime_configuration = {}\n\n            # With the V2 API, the expectation string function had a different signature; the below translates from the new signature to the legacy signature.\n            return legacy_expectation_string_fn(\n                expectation=configuration,\n                styling=runtime_configuration.get(\"styling\", None),\n                include_column_name=runtime_configuration.get(\n                    \"include_column_name\", True\n                ),\n            )\n\n        return expectation_string_fn_with_legacy_translation\n\n    @staticmethod\n    def _get_legacy_v2_api_observed_value(expectation_string_fn, result):\n        if (\n            expectation_string_fn.__name__\n            != \"expectation_string_fn_with_legacy_translation\"\n        ):\n            # If legacy V2 API style rendering is used, \"expectation_string_fn\" will be the method defined in the above \"_get_legacy_v2_api_style_expectation_string_fn\".\n            # If this isn't the case, return None, so we don't do any legacy logic.\n            return None\n\n        # With V2 API style rendering, the result had an \"observed_value\" entry that could be rendered.\n        return result[\"result\"].get(\"observed_value\")\n", "path": "great_expectations/render/renderer/content_block/validation_results_table_content_block.py"}]}