launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24614
[Merge] ~cjwatson/launchpad:simplify-module-hacks into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:simplify-module-hacks into launchpad:master.
Commit message:
Don't try to set __module__ on created interfaces
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/382816
zope.interface 5.0.0 makes __module__ read-only. Instead, set it when creating the interface; while we're at it, use a temporary module rather than stuffing things into lp.testing.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:simplify-module-hacks into launchpad:master.
diff --git a/lib/lp/services/webapp/doc/canonical_url.txt b/lib/lp/services/webapp/doc/canonical_url.txt
index 8a52aa7..1082d4b 100644
--- a/lib/lp/services/webapp/doc/canonical_url.txt
+++ b/lib/lp/services/webapp/doc/canonical_url.txt
@@ -9,34 +9,31 @@ The browser:url directive registers an ICanonicalUrlData adapter.
In this test, we'll use a URL hierarchy /countries/England/+towns/London
In this test, we'll use interfaces ICountrySet, ICountry and ITown, which we
-will put in lp.testing.
+will put in a temporary module.
+ >>> import sys
+ >>> import types
>>> from lp.services.webapp.interfaces import ICanonicalUrlData
>>> from zope.interface import Interface, Attribute, implementer
+ >>> module = types.ModuleType(factory.getUniqueString().replace('-', '_'))
+ >>> sys.modules[module.__name__] = module
+
>>> class ICountrySet(Interface):
- ... pass
+ ... __module__ = module.__name__
>>> class ICountry(Interface):
+ ... __module__ = module.__name__
... name = Attribute('the name of this country')
>>> class ITown(Interface):
... """Dummy interface for use in browser:url tests."""
+ ... __module__ = module.__name__
... country = Attribute('the country the town is in')
... name = Attribute('the name of this town')
-XXX: This is evil, as it changes the hash of the interfaces. It *must* be done
-before they're registered anywhere.
-
-Put the interfaces into lp.testing, ensuring that there
-are not already objects with those names there.
-
- >>> import lp.testing
>>> for interface in ICountrySet, ICountry, ITown:
- ... name = interface.getName()
- ... assert getattr(lp.testing, name, None) is None
- ... setattr(lp.testing, name, interface)
- ... interface.__module__ = 'lp.testing'
+ ... setattr(module, interface.getName(), interface)
Add a view for Country/+map.
@@ -107,27 +104,27 @@ Configure a browser:url for ITown. Our first attempt fails because we mistyped
... <include package="zope.component" file="meta.zcml" />
... <include package="lp.services.webapp" file="meta.zcml" />
... <browser:url
- ... for="lp.testing.ITown"
- ... path_expression="string:+towns/${name}"
+ ... for="{module_name}.ITown"
+ ... path_expression="string:+towns/${{name}}"
... attribute_to_parent="countryOopsTypo"
... />
... </configure>
- ... """)
+ ... """.format(module_name=module.__name__))
Traceback (most recent call last):
...
ZopeXMLConfigurationError: File "<string>", line ...
- AttributeError: The name "countryOopsTypo" is not in lp.testing.ITown
+ AttributeError: The name "countryOopsTypo" is not in ....ITown
>>> zcmlcontext = xmlconfig.string("""
... <configure xmlns:browser="http://namespaces.zope.org/browser">
... <include package="lp.services.webapp" file="meta.zcml" />
... <browser:url
- ... for="lp.testing.ITown"
- ... path_expression="string:+towns/${name}"
+ ... for="{module_name}.ITown"
+ ... path_expression="string:+towns/${{name}}"
... attribute_to_parent="country"
... />
... </configure>
- ... """)
+ ... """.format(module_name=module.__name__))
Now, there is an ICanonicalUrlData registered for ITown.
@@ -143,12 +140,9 @@ Now, there is an ICanonicalUrlData registered for ITown.
The parent of an object might be accessible via an attribute, or it might
be a utility. This is the case for an ICountry object: its parent is the
ICountrySet. I need to put the countryset_instance somewhere we can get
-at it from zcml. I'll put it in lp.testing.
-
- >>> assert getattr(
- ... lp.testing, 'countryset_instance', None) is None
+at it from zcml. I'll put it in our temporary module.
- >>> lp.testing.countryset_instance = countryset_instance
+ >>> module.countryset_instance = countryset_instance
>>> zcmlcontext = xmlconfig.string("""
... <configure
@@ -160,16 +154,16 @@ at it from zcml. I'll put it in lp.testing.
... <include file="meta.zcml" />
... </configure>
... <utility
- ... provides="lp.testing.ICountrySet"
- ... component="lp.testing.countryset_instance"
+ ... provides="{module_name}.ICountrySet"
+ ... component="{module_name}.countryset_instance"
... />
... <browser:url
- ... for="lp.testing.ICountry"
+ ... for="{module_name}.ICountry"
... path_expression="name"
- ... parent_utility="lp.testing.ICountrySet"
+ ... parent_utility="{module_name}.ICountrySet"
... />
... </configure>
- ... """)
+ ... """.format(module_name=module.__name__))
Now, there is an ICanonicalUrlData registered for ICountry.
@@ -208,19 +202,19 @@ an adapter.
... return getUtility(ILaunchpadRoot)
The CountrySetUrl class needs to be accessible from zcml. So, we put it
-in lp.testing.
+in our temporary module.
- >>> lp.testing.CountrySetUrl = CountrySetUrl
+ >>> module.CountrySetUrl = CountrySetUrl
>>> zcmlcontext = xmlconfig.string("""
... <configure xmlns:browser="http://namespaces.zope.org/browser">
... <include package="lp.services.webapp" file="meta.zcml" />
... <browser:url
- ... for="lp.testing.ICountrySet"
- ... urldata="lp.testing.CountrySetUrl"
+ ... for="{module_name}.ICountrySet"
+ ... urldata="{module_name}.CountrySetUrl"
... />
... </configure>
- ... """)
+ ... """.format(module_name=module.__name__))
Now, there is an ICanonicalUrlData registered for ICountrySet.
@@ -438,17 +432,17 @@ And if the configuration does provide a rootsite:
... <include package="zope.component" file="meta.zcml" />
... <include package="lp.services.webapp" file="meta.zcml" />
... <utility
- ... provides="lp.testing.ICountrySet"
- ... component="lp.testing.countryset_instance"
+ ... provides="{module_name}.ICountrySet"
+ ... component="{module_name}.countryset_instance"
... />
... <browser:url
- ... for="lp.testing.ICountry"
+ ... for="{module_name}.ICountry"
... path_expression="name"
- ... parent_utility="lp.testing.ICountrySet"
+ ... parent_utility="{module_name}.ICountrySet"
... rootsite="bugs"
... />
... </configure>
- ... """)
+ ... """.format(module_name=module.__name__))
>>> canonical_url(country_instance)
u'http://bugs.launchpad.test/countries/England'
@@ -551,10 +545,7 @@ only the relative local path returned.
== The end ==
-We've finished with our interfaces and utility component, so remove them from
-lp.testing.
-
- >>> for name in ['ICountrySet', 'ICountry', 'ITown', 'countryset_instance',
- ... 'CountrySetUrl']:
- ... delattr(lp.testing, name)
+We've finished with our interfaces and utility component, so remove the
+temporary module.
+ >>> del sys.modules[module.__name__]
diff --git a/lib/lp/services/webapp/doc/menus.txt b/lib/lp/services/webapp/doc/menus.txt
index d29f08e..e94d670 100644
--- a/lib/lp/services/webapp/doc/menus.txt
+++ b/lib/lp/services/webapp/doc/menus.txt
@@ -546,30 +546,27 @@ they are as we expect.
== Registering menus in ZCML ==
-First, we define a couple of interfaces, and put them in the
-lp.testing module.
+First, we define a couple of interfaces, and put them in a temporary module.
+
+ >>> import sys
+ >>> import types
+
+ >>> module = types.ModuleType(factory.getUniqueString().replace('-', '_'))
+ >>> sys.modules[module.__name__] = module
>>> class IThingHavingFacets(Interface):
- ... pass
- >>> import lp.testing
- >>> getattr(lp.testing, 'IThingHavingFacets', None) is None
- True
+ ... __module__ = module.__name__
- >>> lp.testing.IThingHavingFacets = IThingHavingFacets
- >>> IThingHavingFacets.__module__ = 'lp.testing'
+ >>> module.IThingHavingFacets = IThingHavingFacets
>>> class IThingHavingMenus(Interface):
- ... pass
- >>> import lp.testing
- >>> getattr(lp.testing, 'IThingHavingMenus', None) is None
- True
+ ... __module__ = module.__name__
- >>> lp.testing.IThingHavingMenus = IThingHavingMenus
- >>> IThingHavingMenus.__module__ = 'lp.testing'
+ >>> module.IThingHavingMenus = IThingHavingMenus
Next, we define a FacetMenu subclass to be used for IThingHavingFacets,
using a usedfor class attribute to say what interface it is to be
-registered for, and put it too in the lp.testing module.
+registered for, and put it too in our temporary module.
>>> class FacetsForThing(Facets):
... usedfor = IThingHavingFacets
@@ -585,10 +582,7 @@ registered for, and put it too in the lp.testing module.
... summary = self.request.method
... return Link(target, text, summary=summary)
- >>> getattr(lp.testing, 'FacetsForThing', None) is None
- True
-
- >>> lp.testing.FacetsForThing = FacetsForThing
+ >>> module.FacetsForThing = FacetsForThing
And likewise for an application menu registered for IThingHavingMenus.
@@ -596,20 +590,14 @@ And likewise for an application menu registered for IThingHavingMenus.
... usedfor = IThingHavingMenus
... facet = 'foo'
- >>> getattr(lp.testing, 'FooMenuForThing', None) is None
- True
-
- >>> lp.testing.FooMenuForThing = FooMenuForThing
+ >>> module.FooMenuForThing = FooMenuForThing
We do the same for a context menu.
>>> class ContextMenuForThing(MyContextMenu):
... usedfor = IThingHavingMenus
- >>> print getattr(lp.testing, 'ContextMenuForThing', None)
- None
-
- >>> lp.testing.ContextMenuForThing = ContextMenuForThing
+ >>> module.ContextMenuForThing = ContextMenuForThing
Now, check that we have no IFacetMenu adapter for an IThingHavingFacets
object.
@@ -641,11 +629,11 @@ Same for an IContextMenu adapter.
... <configure xmlns:browser="http://namespaces.zope.org/browser">
... <include file="lib/lp/services/webapp/meta.zcml" />
... <browser:menus
- ... module="lp.testing"
+ ... module="{module_name}"
... classes="FacetsForThing FooMenuForThing ContextMenuForThing"
... />
... </configure>
- ... """)
+ ... """.format(module_name=module.__name__))
>>> menu1 = IFacetMenu(something_with_facets)
>>> menu1.context = something_with_facets
@@ -885,14 +873,9 @@ render() method.
== Cleaning up ==
-We're done testing the zcml, so we can clean up the
-lp.testing module.
+We're done testing the zcml, so we can clean up the temporary module.
- >>> del lp.testing.FacetsForThing
- >>> del lp.testing.FooMenuForThing
- >>> del lp.testing.ContextMenuForThing
- >>> del lp.testing.IThingHavingFacets
- >>> del lp.testing.IThingHavingMenus
+ >>> del sys.modules[module.__name__]
== The enabled_with_permission function decorator ==