Allow overriding of assets
authorKarl O. Pinc <kop@karlpinc.com>
Tue, 8 Dec 2020 23:26:38 +0000 (17:26 -0600)
committerKarl O. Pinc <kop@karlpinc.com>
Tue, 8 Dec 2020 23:26:38 +0000 (17:26 -0600)
examples/etc/pgwui.ini
examples/misc/development.ini
src/pgwui_server/pgwui_server.py
tests/test_pgwui_server.py

index 1eaa1eb659c9fa11e0f5b985b6cbbc4037361133..f38238599a7dd929b0d3009f1214b5651c3019d2 100644 (file)
@@ -152,6 +152,33 @@ pgwui.dry_run = False
 #   pgwui_logout = /logout
 #   pgwui_upload = /upload
 
+# Overriding assets
+#
+# The visual presentation of a PGWUI component is controlled by its assets.
+# Overriding assets allows for extensive customization of presentation.
+#
+# A Pyramid asset is any file included in a Pyramid application that is
+# not a Python source code file.  So assets are image files, Mako template
+# files used to render pages, CSS files, JavaScript files, etc.
+#
+# See:
+# https://docs.pylonsproject.org/projects/pyramid/en/1.10-branch/narr/assets.html
+#
+# By default no assets are overridden.  Override assets with:
+#
+# pgwui.override_assets =
+#   asset = new
+#
+# 'asset' is the asset to override, a Pyramid asset specification
+#
+# 'new' is the new value either a Pyramid asset specification
+#       or a file system path
+#
+# Example, altering the menu presented by PGWUI_Menu:
+#
+#    pgwui.override_assets =
+#      pgwui_menu:templates/menu.mak = /tmp/mymenu.mak
+
 # Settings validation
 
 # Whether or not to validate the session.secret setting.  (optional)
index 9ea841f34e3e5a0caf8b91da93a8edd71ad74bf8..80974faa5211fc56be8dd37b5b19584d7773e947 100644 (file)
@@ -157,6 +157,33 @@ pgwui.dry_run = False
 #   pgwui_logout = /logout
 #   pgwui_upload = /upload
 
+# Overriding assets
+#
+# The visual presentation of a PGWUI component is controlled by its assets.
+# Overriding assets allows for extensive customization of presentation.
+#
+# A Pyramid asset is any file included in a Pyramid application that is
+# not a Python source code file.  So assets are image files, Mako template
+# files used to render pages, CSS files, JavaScript files, etc.
+#
+# See:
+# https://docs.pylonsproject.org/projects/pyramid/en/1.10-branch/narr/assets.html
+#
+# By default no assets are overridden.  Override assets with:
+#
+# pgwui.override_assets =
+#   asset = new
+#
+# 'asset' is the asset to override, a Pyramid asset specification
+#
+# 'new' is the new value either a Pyramid asset specification
+#       or a file system path
+#
+# Example, altering the menu presented by PGWUI_Menu:
+#
+#    pgwui.override_assets =
+#      pgwui_menu:templates/menu.mak = /tmp/mymenu.mak
+
 # Settings validation
 
 # Whether or not to validate the session.secret setting.  (optional)
index 4a4bd54ee877b22a74268423b9b42386e3e2dca6..cb668a63f24bb1849cd021bcb9d9acf9565e9e8e 100644 (file)
@@ -25,10 +25,12 @@ WSGI server.
 '''
 
 from pyramid.config import Configurator
+import pyramid.exceptions
 import logging
 import sys
 
 from . import exceptions as server_ex
+from pgwui_common import assets
 from pgwui_common import check_settings
 from pgwui_common import exceptions as common_ex
 from pgwui_common import routes
@@ -53,6 +55,7 @@ MULTI_SETTINGS = set(
     ['routes',
      'home_page',
      'menu_page',
+     'override_assets',
      ])
 
 # Default settings
@@ -238,7 +241,8 @@ def apply_component_defaults(settings, components):
                 config.include(component)
             routes.add_routes(config, settings)
         log.debug('Done autoconfiguring PGWUI components')
-        return config
+        errors = assets.override_assets(config, settings)
+        return (config, errors)
 
 
 def pgwui_server_config(settings):
@@ -246,8 +250,11 @@ def pgwui_server_config(settings):
     '''
     components = plugin.find_pgwui_components()
     exit_on_invalid_settings(settings, components)
-    config = apply_component_defaults(settings, components)
-    errors = pgwui_common.urls.add_urls_setting(config, settings)
+    try:
+        (config, errors) = apply_component_defaults(settings, components)
+    except pyramid.exceptions.ConfigurationError as exp:
+        exit_reporting_errors([common_ex.BadSettingError(exp)])
+    errors.extend(pgwui_common.urls.add_urls_setting(config, settings))
     if errors:
         exit_reporting_errors(errors)
     return config
index 75ffbcb0c9ad3682f3e6ac253f00605bf067816f..f64b6b1e77b1292825b04ce8023582900a44688f 100644 (file)
 import copy
 import logging
 import pytest
+import pyramid.exceptions
 import sys
 
+import pgwui_common.assets
 import pgwui_common.exceptions as common_ex
 import pgwui_common.check_settings
 import pgwui_common.plugin
@@ -46,6 +48,9 @@ pytestmark = pytest.mark.unittest
 MockConfigurator = testing.make_magicmock_fixture(
     pgwui_server, 'Configurator')
 
+mock_override_assets = testing.make_mock_fixture(
+    pgwui_common.assets, 'override_assets')
+
 mock_find_pgwui_components = testing.make_mock_fixture(
     pgwui_common.plugin, 'find_pgwui_components')
 mock_find_pgwui_check_settings = testing.make_mock_fixture(
@@ -437,8 +442,12 @@ def test_exit_on_invalid_settings_invalid(
         errors.append('error1')
 
     mock_dictify_settings.side_effect = mymock
+    mock_exit_reporting_errors.side_effect = lambda *args: sys.exit(1)
 
-    pgwui_server.exit_on_invalid_settings({}, [])
+    with pytest.raises(SystemExit) as excinfo:
+        pgwui_server.exit_on_invalid_settings({}, [])
+
+        assert excinfo[1].code == 1
 
     mock_dictify_settings.assert_called_once()
     mock_validate_settings.assert_called_once()
@@ -453,7 +462,7 @@ def test_exit_on_invalid_settings_valid(
     '''
     pgwui_server.exit_on_invalid_settings({}, [])
 
-    assert True
+    assert mock_exit_reporting_errors.call_count == 0
 
 
 mock_exit_on_invalid_settings = testing.make_mock_fixture(
@@ -550,17 +559,23 @@ def test_apply_component_defaults(caplog,
                                   mock_in_development,
                                   MockConfigurator,
                                   mock_autoconfigurable_components,
-                                  mock_add_routes):
+                                  mock_add_routes,
+                                  mock_override_assets):
     '''A configurator is returned, a debug log entry is made for
     each autoconfigurable component
     '''
+    expected_errors = 'some errors'
     caplog.set_level(logging.DEBUG)
 
     mock_autoconfigurable_components.return_value = \
         ['pgwui_mock_component_name']
+    mock_override_assets.return_value = expected_errors
+
+    (config, errors) = pgwui_server.apply_component_defaults(
+        {'pgwui': {}}, [])
 
-    result = pgwui_server.apply_component_defaults({'pgwui': {}}, [])
-    assert str(type(result)) == str(type(MockConfigurator))
+    assert str(type(config)) == str(type(MockConfigurator))
+    assert errors == expected_errors
 
     logs = caplog.record_tuples
 
@@ -585,7 +600,7 @@ mock_add_urls_setting = testing.make_mock_fixture(
     ('errors', 'ere_calls'), [
         ([], 0),
         (['some error'], 1)])
-def test_pgwui_server_config(
+def test_pgwui_server_config_success(
         pyramid_config,
         mock_find_pgwui_components,
         mock_exit_on_invalid_settings,
@@ -593,12 +608,18 @@ def test_pgwui_server_config(
         mock_add_urls_setting,
         mock_exit_reporting_errors,
         errors, ere_calls):
-    '''Makes expected calls, returns a configuration
+    '''When apply_component_defaults() returns -- makes expected calls,
+    returns a configuration
     '''
-    mock_apply_component_defaults.return_value = pyramid_config
+    mock_apply_component_defaults.return_value = (pyramid_config, [])
     mock_add_urls_setting.return_value = errors
+    mock_exit_reporting_errors.side_effect = lambda *args: sys.exit(1)
 
-    result = pgwui_server.pgwui_server_config({})
+    if ere_calls:
+        with pytest.raises(SystemExit):
+            result = pgwui_server.pgwui_server_config({})
+    else:
+        result = pgwui_server.pgwui_server_config({})
 
     mock_find_pgwui_components.assert_called_once()
     mock_exit_on_invalid_settings.assert_called_once()
@@ -609,6 +630,26 @@ def test_pgwui_server_config(
         assert result == pyramid_config
 
 
+def test_pgwui_server_config_bad_config(
+        pyramid_config,
+        mock_find_pgwui_components,
+        mock_exit_on_invalid_settings,
+        mock_apply_component_defaults,
+        mock_add_urls_setting,
+        mock_exit_reporting_errors):
+    '''When apply_component_defaults() raises a configuration exception
+    exit_reporting_errors() is called
+    '''
+    mock_apply_component_defaults.side_effect = \
+        pyramid.exceptions.ConfigurationError
+    mock_exit_reporting_errors.side_effect = lambda *args: sys.exit(1)
+
+    with pytest.raises(SystemExit):
+        pgwui_server.pgwui_server_config({})
+
+    assert mock_exit_reporting_errors.call_count == 1
+
+
 mock_pgwui_server_config = testing.make_mock_fixture(
     pgwui_server, 'pgwui_server_config')