From 8e037fda9af695b608240d8fed085c403f657011 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 1 May 2009 09:06:54 +0000 Subject: - In previous releases, the ``repoze.bfg.url.model_url``, ``repoze.bfg.traversal.model_path`` and ``repoze.bfg.traversal.model_path_tuple`` functions always ignored the ``__name__`` argument of the root object in a model graph ( effectively replacing it with a leading ``/`` in the returned value) when a path or URL was generated. The code required to perform this operation was not efficient. As of this release, the root object in a model graph *must* have a ``__name__`` attribute that is either ``None`` or the empty string (``''``) for URLs and paths to be generated properly from these APIs. If your root model object has a ``__name__`` argument that is not one of these values, you will need to change your code for URLs and paths to be generated properly. If your model graph has a root node with a string ``__name__`` that is not null, the value of ``__name__`` will be prepended to every path and URL generated. --- CHANGES.txt | 16 ++++++++++++++++ docs/narr/models.rst | 9 +++++++++ repoze/bfg/tests/test_traversal.py | 26 +++++++++++++++++++++++++- repoze/bfg/traversal.py | 27 ++++++++++++++++----------- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index e51c238b4..ded5abc62 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -82,6 +82,22 @@ Features Backwards Incompatibilities --------------------------- +- In previous releases, the ``repoze.bfg.url.model_url``, + ``repoze.bfg.traversal.model_path`` and + ``repoze.bfg.traversal.model_path_tuple`` functions always ignored + the ``__name__`` argument of the root object in a model graph ( + effectively replacing it with a leading ``/`` in the returned value) + when a path or URL was generated. The code required to perform this + operation was not efficient. As of this release, the root object in + a model graph *must* have a ``__name__`` attribute that is either + ``None`` or the empty string (``''``) for URLs and paths to be + generated properly from these APIs. If your root model object has a + ``__name__`` argument that is not one of these values, you will need + to change your code for URLs and paths to be generated properly. If + your model graph has a root node with a string ``__name__`` that is + not null, the value of ``__name__`` will be prepended to every path + and URL generated. + - The ``repoze.bfg.location.LocationProxy`` class and the ``repoze.bfg.location.ClassAndInstanceDescr`` class have both been removed in order to be able to eventually shed a dependency on diff --git a/docs/narr/models.rst b/docs/narr/models.rst index 61e313830..9daa5668d 100644 --- a/docs/narr/models.rst +++ b/docs/narr/models.rst @@ -111,6 +111,15 @@ string. For instance: __name__ = '' __parent__ = None +.. note:: If your root model object has a ``__name__`` argument that + is not ``None`` or the empty string, URLs returned by the + ``repoze.bfg.url.model_url`` function and paths generated by the + ``repoze.bfg.traversal.model_path`` and + ``repoze.bfg.traversal.model_path_tuple`` APIs will be generated + improperly. The value of ``__name__`` will be prepended to every + path and URL generated (as opposed to a single leading slash or + empty tuple element). + A node returned from the root item's ``__getitem__`` method should have a ``__parent__`` attribute that is a reference to the root object, and its ``__name__`` attribute should match the name by which diff --git a/repoze/bfg/tests/test_traversal.py b/repoze/bfg/tests/test_traversal.py index f361d0a79..867dae318 100644 --- a/repoze/bfg/tests/test_traversal.py +++ b/repoze/bfg/tests/test_traversal.py @@ -384,7 +384,31 @@ class ModelPathTests(unittest.TestCase): root.__name__ = None result = self._callFUT(root) self.assertEqual(result, '/') - + + def test_root_default_emptystring(self): + root = DummyContext() + root.__parent__ = None + root.__name__ = '' + result = self._callFUT(root) + self.assertEqual(result, '/') + + def test_root_object_nonnull_name_direct(self): + root = DummyContext() + root.__parent__ = None + root.__name__ = 'flubadub' + result = self._callFUT(root) + self.assertEqual(result, 'flubadub') # insane case + + def test_root_object_nonnull_name_indirect(self): + root = DummyContext() + root.__parent__ = None + root.__name__ = 'flubadub' + other = DummyContext() + other.__parent__ = root + other.__name__ = 'barker' + result = self._callFUT(other) + self.assertEqual(result, 'flubadub/barker') # insane case + def test_nonroot_default(self): root = DummyContext() root.__parent__ = None diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py index f4f64484f..9da1818fc 100644 --- a/repoze/bfg/traversal.py +++ b/repoze/bfg/traversal.py @@ -172,12 +172,14 @@ def model_path(model, *elements): instance, if one of the models in your graph has a ``__name__`` which (by error) is a dictionary, the ``model_path`` function will attempt to append it to a - string and it will cause a TypeError. A single - exception to this rule exists: the :term:`root` model - may have a ``__name__`` attribute of any value; the - value of this attribute will always be ignored (and - effectively replaced with a leading ``/``) when the path - is generated. + string and it will cause a TypeError. + + .. note:: The the :term:`root` model *must* have a ``__name__`` + attribute with a value of either ``None`` or the empty + string for paths to be generated properly. If the root + model has a non-null ``__name__`` attribute, its name + will be prepended to the generated path rather than a + single leading '/' character. """ path = _model_path_list(model, *elements) return path and '/'.join([quote_path_segment(x) for x in path]) or '/' @@ -210,11 +212,14 @@ def model_path_tuple(model, *elements): instance, if one of the models in your graph has a ``__name__`` which (by error) is a dictionary, that dictionary will be placed in the path tuple; no warning - or error will be given. A single exception to this rule - exists: the :term:`root` model may have a ``__name__`` - attribute of any value; the value of this attribute will - always be ignored (and effectively replaced with ``''``) - when the path is generated. + or error will be given. + + .. note:: The the :term:`root` model *must* have a ``__name__`` + attribute with a value of either ``None`` or the empty + string for path tuples to be generated properly. If + the root model has a non-null ``__name__`` attribute, + its name will be the first element in the generated + path tuple rather than the empty string. """ return tuple(_model_path_list(model, *elements)) -- cgit v1.2.3