Repository: great-expectations/great_expectations

Issue:
docs build crashes with UnboundLocalError when data asset name is an integer
**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Use a specific validation result that cannot be shared here.
2. `great_expectations docs build`
4. See error

```
❯ great_expectations docs build

The following Data Docs sites will be built:

 - local_site: file:///Users/taylor/repos/sdap/ge/great_expectations/uncommitted/data_docs/local_site/index.html

Would you like to proceed? [Y/n]:  

Building Data Docs...

--- Logging error ---
Traceback (most recent call last):
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/site_builder.py", line 443, in build
    rendered_content = self.renderer_class.render(resource)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/page_renderer.py", line 210, in render
    page_title += " / " + data_asset_name
TypeError: can only concatenate str (not "int") to str

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/logging/__init__.py", line 1081, in emit
    msg = self.format(record)
  File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/logging/__init__.py", line 925, in format
    return fmt.format(record)
  File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/logging/__init__.py", line 664, in format
    record.message = record.getMessage()
  File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/logging/__init__.py", line 369, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
  File "/Users/taylor/repos/sdap/.venv/bin/great_expectations", line 8, in <module>
    sys.exit(main())
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/cli/cli.py", line 73, in main
    cli()
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/cli/docs.py", line 45, in docs_build
    build_docs(context, site_name=site_name, view=view, assume_yes=assume_yes)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/cli/docs.py", line 146, in build_docs
    index_page_locator_infos = context.build_data_docs(site_names=site_names)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/core/usage_statistics/usage_statistics.py", line 257, in usage_statistics_wrapped_method
    result = func(*args, **kwargs)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/data_context/data_context.py", line 1572, in build_data_docs
    index_page_resource_identifier_tuple = site_builder.build(
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/site_builder.py", line 290, in build
    site_section_builder.build(resource_identifiers=resource_identifiers)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/site_builder.py", line 460, in build
    logger.error(exception_message, e, exc_info=True)
Message: 'An unexpected Exception occurred during data docs rendering.  Because of this error, certain parts of data docs will not be rendered properly and/or may not appear altogether.  Please use the trace, included in this message, to diagnose and repair the underlying issue.  Detailed information follows:\n                TypeError: "can only concatenate str (not "int") to str".  Traceback: "Traceback (most recent call last):\n  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/site_builder.py", line 443, in build\n    rendered_content = self.renderer_class.render(resource)\n  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/page_renderer.py", line 210, in render\n    page_title += " / " + data_asset_name\nTypeError: can only concatenate str (not "int") to str\n".'
Arguments: (TypeError('can only concatenate str (not "int") to str'),)
Traceback (most recent call last):
  File "/Users/taylor/repos/sdap/.venv/bin/great_expectations", line 8, in <module>
    sys.exit(main())
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/cli/cli.py", line 73, in main
    cli()
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/cli/docs.py", line 45, in docs_build
    build_docs(context, site_name=site_name, view=view, assume_yes=assume_yes)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/cli/docs.py", line 146, in build_docs
    index_page_locator_infos = context.build_data_docs(site_names=site_names)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/core/usage_statistics/usage_statistics.py", line 257, in usage_statistics_wrapped_method
    result = func(*args, **kwargs)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/data_context/data_context.py", line 1572, in build_data_docs
    index_page_resource_identifier_tuple = site_builder.build(
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/site_builder.py", line 290, in build
    site_section_builder.build(resource_identifiers=resource_identifiers)
  File "/Users/taylor/repos/sdap/.venv/lib/python3.8/site-packages/great_expectations/render/renderer/site_builder.py", line 466, in build
    viewable_content,
UnboundLocalError: local variable 'viewable_content' referenced before assignment
```

**Expected behavior**
Docs should build.

**Environment (please complete the following information):**
 - OS: [e.g. iOS] macOS and windows 10
 - GE Version: [e.g. 0.10.0] 0.12.1


Discussion:

Resolving patch:
diff --git a/great_expectations/render/renderer/page_renderer.py b/great_expectations/render/renderer/page_renderer.py
--- a/great_expectations/render/renderer/page_renderer.py
+++ b/great_expectations/render/renderer/page_renderer.py
@@ -205,12 +205,12 @@ def render(self, validation_results: ExpectationSuiteValidationResult):
         if run_name_as_time != run_time_datetime and run_name_as_time != "__none__":
             include_run_name = True
 
-        page_title = "Validations / " + expectation_suite_name
+        page_title = "Validations / " + str(expectation_suite_name)
         if data_asset_name:
-            page_title += " / " + data_asset_name
+            page_title += " / " + str(data_asset_name)
         if include_run_name:
-            page_title += " / " + run_name
-        page_title += " / " + run_time
+            page_title += " / " + str(run_name)
+        page_title += " / " + str(run_time)
 
         return RenderedDocumentContent(
             **{
@@ -230,7 +230,7 @@ def _render_validation_header(cls, validation_results):
         expectation_suite_path_components = (
             [".." for _ in range(len(expectation_suite_name.split(".")) + 3)]
             + ["expectations"]
-            + expectation_suite_name.split(".")
+            + str(expectation_suite_name).split(".")
         )
         expectation_suite_path = (
             os.path.join(*expectation_suite_path_components) + ".html"
@@ -546,7 +546,7 @@ def render(self, expectations):
         return RenderedDocumentContent(
             **{
                 "renderer_type": "ExpectationSuitePageRenderer",
-                "page_title": "Expectations / " + expectation_suite_name,
+                "page_title": "Expectations / " + str(expectation_suite_name),
                 "expectation_suite_name": expectation_suite_name,
                 "utm_medium": "expectation-suite-page",
                 "sections": sections,
@@ -820,12 +820,12 @@ def render(self, validation_results):
         if run_name_as_time != run_time_datetime and run_name_as_time != "__none__":
             include_run_name = True
 
-        page_title = "Profiling Results / " + expectation_suite_name
+        page_title = "Profiling Results / " + str(expectation_suite_name)
         if data_asset_name:
-            page_title += " / " + data_asset_name
+            page_title += " / " + str(data_asset_name)
         if include_run_name:
-            page_title += " / " + run_name
-        page_title += " / " + run_time
+            page_title += " / " + str(run_name)
+        page_title += " / " + str(run_time)
 
         return RenderedDocumentContent(
             **{
diff --git a/great_expectations/render/renderer/site_builder.py b/great_expectations/render/renderer/site_builder.py
--- a/great_expectations/render/renderer/site_builder.py
+++ b/great_expectations/render/renderer/site_builder.py
@@ -446,6 +446,13 @@ def build(self, resource_identifiers=None):
                     data_context_id=self.data_context_id,
                     show_how_to_buttons=self.show_how_to_buttons,
                 )
+
+                self.target_store.set(
+                    SiteSectionIdentifier(
+                        site_section_name=self.name, resource_identifier=resource_key,
+                    ),
+                    viewable_content,
+                )
             except Exception as e:
                 exception_message = f"""\
 An unexpected Exception occurred during data docs rendering.  Because of this error, certain parts of data docs will \
@@ -459,13 +466,6 @@ def build(self, resource_identifiers=None):
                 )
                 logger.error(exception_message, e, exc_info=True)
 
-            self.target_store.set(
-                SiteSectionIdentifier(
-                    site_section_name=self.name, resource_identifier=resource_key,
-                ),
-                viewable_content,
-            )
-
 
 class DefaultSiteIndexBuilder:
     def __init__(


Test patch: