From 6cc96689989a7781f1da4ae05b0fbc38e6c8fdb9 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 29 Jun 2009 03:16:10 +0000 Subject: Add changelog entry for resource directive. Rejigger error detection ordering. --- CHANGES.txt | 74 +++++++++++++++++++++++++++++++++++++++++++ repoze/bfg/tests/test_zcml.py | 6 ++-- repoze/bfg/zcml.py | 24 +++++++------- 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 4d86a66cb..afb49e1b2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,80 @@ Next release Features -------- +- A new ZCML directive exists named "resource". This ZCML directive + allows you to override Chameleon templates within a package (both + directories full of templates and individual template files) with + other templates in the same package or within another package. This + allows you to "fake out" a view's use of a template, causing it to + retrieve a different template than the one actually named by a + relative path to a call like + ``render_template_to_response('templates/mytemplate.pt')``. For + example, you can override a template file by doing:: + + + + The string passed to "to_override" and "override_with" is named a + "specification". The colon separator in a specification separates + the package name from a package-relative directory name. The colon + and the following relative path are optional. If they are not + specified, the override attempts to resolve every lookup into a + package from the directory of another package. For example:: + + + + + Individual subdirectories within a package can also be overridden:: + + + + If you wish to override a directory with another directory, you must + make sure to attach the slash to the end of both the ``to_override`` + specification and the ``override_with`` specification. If you fail + to attach a slash to the end of a specification that points a + directory, you will get unexpected results. You cannot override a + directory specification with a file specification, and vice versa (a + startup error will occur if you try). + + You cannot override a resource with itself (a startup error will + occur if you try). + + Only individual *package* resources may be overridden. Overrides + will not traverse through subpackages within an overridden package. + This means that if you want to override resources for both + ``some.package:templates``, and ``some.package.views:templates``, + you will need to register two overrides. + + The package name in a specification may start with a dot, meaning + that the package is relative to the package in which the ZCML file + resides. For example: + + + + Overrides for the same ``to_overrides`` specification can be named + multiple times within ZCML. Each ``override_with`` path will be + consulted in the order defined within ZCML, forming an override + search path. + + Resource overrides can actually override resources other than + templates. Any software which uses the ``pkg_resources`` + ``get_resource_filename``, ``get_resource_stream`` or + ``get_resource_string`` APIs will obtain an overridden file when an + override is used. However, the only built-in facility which uses + the ``pkg_resources`` API within BFG is the templating stuff, so we + only call out template overrides here. + - Use the ``pkg_resources`` API to locate template filenames instead of dead-reckoning using the ``os.path`` module. diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py index 875628f5f..a8eec3d48 100644 --- a/repoze/bfg/tests/test_zcml.py +++ b/repoze/bfg/tests/test_zcml.py @@ -864,12 +864,14 @@ class TestResourceDirective(unittest.TestCase): def test_override_directory_with_file(self): from zope.configuration.exceptions import ConfigurationError context = DummyContext() - self.assertRaises(ConfigurationError, self._callFUT, context, 'a/', 'a') + self.assertRaises(ConfigurationError, self._callFUT, context, + 'a:foo/', 'a:foo.pt') def test_override_file_with_directory(self): from zope.configuration.exceptions import ConfigurationError context = DummyContext() - self.assertRaises(ConfigurationError, self._callFUT, context, 'a', 'a/') + self.assertRaises(ConfigurationError, self._callFUT, context, + 'a:foo.pt', 'a:foo/') def test_no_colons(self): from repoze.bfg.zcml import _override diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index 38db4ead7..14b843bb1 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -192,18 +192,6 @@ def resource(context, to_override, override_with): if to_override == override_with: raise ConfigurationError('You cannot override a resource with itself') - if to_override.endswith('/'): - if not override_with.endswith('/'): - raise ConfigurationError( - 'A directory cannot be overridden with a file (put a slash ' - 'at the end of override_with if necessary)') - - if override_with.endswith('/'): - if not to_override.endswith('/'): - raise ConfigurationError( - 'A file cannot be overridden with a directory (put a slash ' - 'at the end of to_override if necessary)') - package = to_override path = '' if ':' in to_override: @@ -214,6 +202,18 @@ def resource(context, to_override, override_with): if ':' in override_with: override_package, override_prefix = override_with.split(':', 1) + if path.endswith('/'): + if not override_prefix.endswith('/'): + raise ConfigurationError( + 'A directory cannot be overridden with a file (put a slash ' + 'at the end of override_with if necessary)') + + if override_prefix.endswith('/'): + if not path.endswith('/'): + raise ConfigurationError( + 'A file cannot be overridden with a directory (put a slash ' + 'at the end of to_override if necessary)') + package = context.resolve(package).__name__ override_package = context.resolve(package).__name__ -- cgit v1.2.3