[Checkins] SVN: z3reload/trunk/ Initial import of z3reload code.

Gintautas Miliauskas gintas at pov.lt
Sun Aug 10 20:21:50 EDT 2008


Log message for revision 89606:
  Initial import of z3reload code.
  

Changed:
  A   z3reload/trunk/
  A   z3reload/trunk/README.txt
  A   z3reload/trunk/__init__.py
  A   z3reload/trunk/configure.zcml
  A   z3reload/trunk/ftests/
  A   z3reload/trunk/ftests/__init__.py
  A   z3reload/trunk/ftests/dynamic.pt
  A   z3reload/trunk/ftests/dynamic.py
  A   z3reload/trunk/ftests/dynamic_orig.py
  A   z3reload/trunk/ftests/ftesting.zcml
  A   z3reload/trunk/ftests/reload.txt
  A   z3reload/trunk/ftests/tests.py
  A   z3reload/trunk/meta.zcml
  A   z3reload/trunk/metaconfigure.py
  A   z3reload/trunk/metadirectives.py
  A   z3reload/trunk/package-includes/
  A   z3reload/trunk/package-includes/z3reload-configure.zcml
  A   z3reload/trunk/package-includes/z3reload-ftesting.zcml
  A   z3reload/trunk/package-includes/z3reload-meta.zcml
  A   z3reload/trunk/reload.py
  A   z3reload/trunk/subscriber.py

-=-
Added: z3reload/trunk/README.txt
===================================================================
--- z3reload/trunk/README.txt	                        (rev 0)
+++ z3reload/trunk/README.txt	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,123 @@
+z3reload
+========
+
+Version 0.1
+
+http://gintas.pov.lt/z3reload
+
+
+z3reload is a Zope 3 product that enables automatic reloading of view code.
+
+Make sure to read the *pitfalls* section before you delve in.
+
+View instances are short-lived and references to them are stored very
+infrequently, which makes them a good candidate for dynamic reloading.
+In addition they are frequently the largest and most complex part of
+the code in a typical web application.  Even within the restrictions of
+this implementation automatic code reloading is very handy to have as Zope 3
+can take a while to restart.
+
+Code of z3reload now resides at the Zope 3 Base (http://codespeak.net/z3).
+Use the following command to grab the latest trunk using Subversion:
+
+  svn checkout http://codespeak.net/svn/z3/z3reload/trunk z3reload
+
+
+Installation
+------------
+
+Copy the z3reload directory where Zope 3 can find it, copy all files in
+the package-includes/ subdirectory to package-includes/ in Zope 3.
+
+
+Configuration
+-------------
+
+In package-includes/z3reload-configure.zcml (the global one which you created,
+not the one inside the package), the namespace `reload` should be registered,
+like this:
+
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:reload="http://namespaces.pov.lt/z3reload">
+
+In the same file you can specify individual classes, modules or packages which
+contain views that should be made reloadable using the ZCML directive
+`reload`.  Here is an example:
+
+<reload:reload
+    classes="somepackage.somemodule.SomeView
+             somepackage.anothermodule.AnotherView"
+    modules="anotherpackage.views"
+    packages="thirdpackage.browser"
+    />
+
+This configuration would make views SomeView and AnotherView reloadable.
+All views directly in anotherpackage.views, for example,
+anotherpackage.views.FooView (but not anotherpackage.views.admin.BarView),
+would be included too.  Finally, all views in all modules that reside
+in thirdpackage.browser would be processed (thirdpackage.browser.XView,
+thirdpackage.browser.admin.YView, etc.).
+
+
+Usage
+-----
+
+Use the views as you normally would.  The view code will be automatically
+reloaded before just before rendering the view each time.
+
+
+Pitfalls
+--------
+
+Only the module that the view code resides in will be reloaded.  E.g., if
+you have a view mypackage.browser.admin.AdminView that inherits from
+mypackage.browser.ViewBase, the mypackage.browser module will not be
+reloaded, and therefore changes in ViewBase will not take effect.
+
+It is important to understand the implications of reloading a Python
+module.  Basically, all objects -- classes, functions and others --
+defined in the top level of the module "change".  Old references
+(frequently in the form of imports) from other modules, however, will
+still point to the old objects.  This way you can end up with two
+different references to distinct versions of the same class, which may
+cause unexpected behaviour with issubclass().  A similar problem can arise
+if the module defines interfaces which other modules use.
+
+z3reload can deal with updated views, but it will not notice changes in
+other components: adapters, utilities, subscribers.  It will work with
+code outside the components (top-level functions and classes other than
+the registered one) though.  This is because Zope 3 stores references to
+the components at startup time.  It should be possible to reload these
+components automatically too, but that would probably require a different
+approach, because we would not be able not use the mixin hack.
+
+In general it is a good idea to only use automatic reloading for
+non-structural changes such as defining or modifying methods of views
+and do an old-fashioned server restart when you make a more significant
+change.
+
+
+Implementation details
+----------------------
+
+z3reload waits for the DatabaseOpened event, when all view registration has
+been completed, and then walks through the global adapter registry.  For
+each view to be processed according to the `reload` directive it installs
+the mixin Reloader.
+
+Actually, Zope 3 ZCML directives that register views do not register the
+plain view class as a multi-adapter.  Instead, they dynamically construct
+a new type which inherits from the given class and from a `simple view` class
+(that would be zope.app.pagetemplate.simpleviewclass.simple for views that
+have page templates defined in ZCML, and
+zope.app.publisher.browser.viewmeta.simple for views that don't).  We use
+this fact and add Reloader as the first base class.
+
+Reloader overrides the __init__() method of the real view.  In this method
+the module of the class is reloaded and the attribute __bases__ of the class
+is updated with a new reference to the reloaded class.  Then __init__ of the
+actual reloaded view is invoked.
+
+
+Gintautas Miliauskas <gintas at pov.lt>
+2005-08-20


Property changes on: z3reload/trunk/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/__init__.py
===================================================================
--- z3reload/trunk/__init__.py	                        (rev 0)
+++ z3reload/trunk/__init__.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,2 @@
+# Set this to True to list processed view classes on stderr.
+BLATHER = False


Property changes on: z3reload/trunk/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/configure.zcml
===================================================================
--- z3reload/trunk/configure.zcml	                        (rev 0)
+++ z3reload/trunk/configure.zcml	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <subscriber
+      for="zope.app.appsetup.interfaces.IDatabaseOpenedEvent"
+      handler=".subscriber.database_opened"
+      />
+
+</configure>


Property changes on: z3reload/trunk/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/ftests/__init__.py
===================================================================


Property changes on: z3reload/trunk/ftests/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/ftests/dynamic.pt
===================================================================
--- z3reload/trunk/ftests/dynamic.pt	                        (rev 0)
+++ z3reload/trunk/ftests/dynamic.pt	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1 @@
+<p>The number is <span tal:replace="view/number" /></p>


Property changes on: z3reload/trunk/ftests/dynamic.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/ftests/dynamic.py
===================================================================
--- z3reload/trunk/ftests/dynamic.py	                        (rev 0)
+++ z3reload/trunk/ftests/dynamic.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,19 @@
+from zope.publisher.browser import BrowserView
+
+
+class SomeNumberView(BrowserView):
+
+    def __init__(self, context, request):
+        BrowserView.__init__(self, context, request)
+        self.number = 1001
+
+
+class AnotherNumberView(BrowserView):
+
+    number = 2001
+
+
+class ThirdNumberView(BrowserView):
+
+    def __call__(self):
+        return '3001'


Property changes on: z3reload/trunk/ftests/dynamic.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/ftests/dynamic_orig.py
===================================================================
--- z3reload/trunk/ftests/dynamic_orig.py	                        (rev 0)
+++ z3reload/trunk/ftests/dynamic_orig.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,19 @@
+from zope.publisher.browser import BrowserView
+
+
+class SomeNumberView(BrowserView):
+
+    def __init__(self, context, request):
+        BrowserView.__init__(self, context, request)
+        self.number = 1001
+
+
+class AnotherNumberView(BrowserView):
+
+    number = 2001
+
+
+class ThirdNumberView(BrowserView):
+
+    def __call__(self):
+        return '3001'


Property changes on: z3reload/trunk/ftests/dynamic_orig.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/ftests/ftesting.zcml
===================================================================
--- z3reload/trunk/ftests/ftesting.zcml	                        (rev 0)
+++ z3reload/trunk/ftests/ftesting.zcml	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,23 @@
+<configure xmlns="http://namespaces.zope.org/browser"
+           xmlns:reload="http://namespaces.pov.lt/z3reload">
+
+  <reload:reload modules="z3reload.ftests.dynamic" />
+
+  <page for="zope.traversing.interfaces.IContainmentRoot"
+        name="some.html"
+        class=".dynamic.SomeNumberView"
+        template="dynamic.pt"
+        permission="zope.Public" />
+
+  <page for="zope.traversing.interfaces.IContainmentRoot"
+        name="another.html"
+        class=".dynamic.AnotherNumberView"
+        template="dynamic.pt"
+        permission="zope.Public" />
+
+  <page for="zope.traversing.interfaces.IContainmentRoot"
+        name="third.txt"
+        class=".dynamic.ThirdNumberView"
+        permission="zope.Public" />
+
+</configure>


Property changes on: z3reload/trunk/ftests/ftesting.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/ftests/reload.txt
===================================================================
--- z3reload/trunk/ftests/reload.txt	                        (rev 0)
+++ z3reload/trunk/ftests/reload.txt	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,73 @@
+z3reload functional test
+========================
+
+
+Quick look
+----------
+
+First, let's simply try looking at the views, to make sure that
+the configuration is correct.
+
+    >>> print http("GET /some.html HTTP/1.1\n", handle_errors=False)
+    HTTP/1.1 200 Ok
+    ...
+    <p>The number is 1001</p>
+    <BLANKLINE>
+
+    >>> print http("GET /another.html HTTP/1.1\n", handle_errors=False)
+    HTTP/1.1 200 Ok
+    ...
+    <p>The number is 2001</p>
+    <BLANKLINE>
+
+    >>> print http("GET /third.txt HTTP/1.1\n", handle_errors=False)
+    HTTP/1.1 200 Ok
+    ...
+    Content-Type: text/plain;charset=utf-8
+    <BLANKLINE>
+    3001
+
+
+Modification
+------------
+
+Now we will modify the view code:
+
+    >>> from z3reload.ftests.tests import openfile
+    >>> import time
+    >>> def replace(old, new):
+    ...     time.sleep(0.5) # longish, but shorter delays don't seem to work
+    ...     orig = openfile('dynamic_orig.py').read()
+    ...     f = openfile('dynamic.py', 'w')
+    ...     f.write(orig.replace(old, new))
+    ...     f.close()
+    ...     time.sleep(0.5) # longish, but shorter delays don't seem to work
+
+    >>> replace('1001', '1123')
+    >>> print http("GET /some.html HTTP/1.1\n", handle_errors=False)
+    HTTP/1.1 200 Ok
+    ...
+    <p>The number is 1123</p>
+    <BLANKLINE>
+
+    >>> replace('2001', '2123')
+    >>> print http("GET /another.html HTTP/1.1\n", handle_errors=False)
+    HTTP/1.1 200 Ok
+    ...
+    <p>The number is 2123</p>
+    <BLANKLINE>
+
+    >>> replace('3001', '3123')
+
+    >>> print http("GET /third.txt HTTP/1.1\n", handle_errors=False)
+    HTTP/1.1 200 Ok
+    ...
+    Content-Type: text/plain;charset=utf-8
+    <BLANKLINE>
+    3123
+
+
+Epilogue
+--------
+
+ vim: ft=rest


Property changes on: z3reload/trunk/ftests/reload.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/ftests/tests.py
===================================================================
--- z3reload/trunk/ftests/tests.py	                        (rev 0)
+++ z3reload/trunk/ftests/tests.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,27 @@
+import os
+import unittest
+
+from zope.testing import doctest
+from zope.app.testing.functional import FunctionalDocFileSuite
+
+
+current_dir = os.path.dirname(__file__)
+
+def openfile(filename, mode='r'):
+    return file(os.path.join(current_dir, filename), mode)
+
+def resetFile(test):
+    dynamic_orig = openfile('dynamic_orig.py').read()
+    openfile('dynamic.py', 'w').write(dynamic_orig)
+
+
+def test_suite():
+    optionflags = (doctest.ELLIPSIS | doctest.REPORT_NDIFF |
+                   doctest.NORMALIZE_WHITESPACE |
+                   doctest.REPORT_ONLY_FIRST_FAILURE)
+    return FunctionalDocFileSuite('reload.txt', optionflags=optionflags,
+                                  setUp=resetFile, tearDown=resetFile)
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: z3reload/trunk/ftests/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/meta.zcml
===================================================================
--- z3reload/trunk/meta.zcml	                        (rev 0)
+++ z3reload/trunk/meta.zcml	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/meta">
+
+  <directives namespace="http://namespaces.pov.lt/z3reload">
+    <directive
+      name="reload"
+      schema=".metadirectives.IReloadDirective"
+      handler=".metaconfigure.reload"
+      />
+  </directives>
+
+</configure>


Property changes on: z3reload/trunk/meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/metaconfigure.py
===================================================================
--- z3reload/trunk/metaconfigure.py	                        (rev 0)
+++ z3reload/trunk/metaconfigure.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,23 @@
+import sys
+from zope.configuration.exceptions import ConfigurationError
+
+
+enabled_classes = [] # list of class objects
+enabled_modules = [] # list of module names
+enabled_packages = [] # list of package names
+
+
+def handle_reload(classes, modules, packages):
+    """Add provided objects to global registry of reloadable objects."""
+    enabled_classes.extend(classes)
+    enabled_modules.extend([mod.__name__ for mod in modules])
+    enabled_packages.extend([pkg.__name__ for pkg in packages])
+
+
+def reload(_context, classes=[], modules=[], packages=[]):
+    """Process the `reload` ZCML directive."""
+    if not (classes or modules or packages):
+        raise ConfigurationError("You must specify at least one of"
+                                 " `classes`, `modules` or `packages`.")
+    _context.action(discriminator=None, callable=handle_reload,
+                    args=(classes, modules, packages))


Property changes on: z3reload/trunk/metaconfigure.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/metadirectives.py
===================================================================
--- z3reload/trunk/metadirectives.py	                        (rev 0)
+++ z3reload/trunk/metadirectives.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,40 @@
+from zope.interface import Interface
+from zope.configuration.fields import Tokens, GlobalObject
+
+
+class IReloadDirective(Interface):
+
+    classes = Tokens(
+        title=u"View classes",
+        required=False,
+        value_type=GlobalObject(
+                title=u"View class",
+                description=u"""
+                A view class for which automatic reload should be enabled.
+                """))
+
+    modules = Tokens(
+        title=u"Modules",
+        required=False,
+        value_type=GlobalObject(
+                title=u"Module",
+                description=u"""
+                A module containing views for which automatic reload should be
+                enabled.
+                """))
+
+    packages = Tokens(
+        title=u"Packages",
+        required=False,
+        value_type=GlobalObject(
+            title=u"Package",
+            description=u"""
+            A package containing views for which automatic reload should be
+            enabled.
+
+            `module` only works for a single module, whereas `package` also
+            applies for contained modules and packages.
+            """))
+
+
+# TODO: reload:omit, reload:all


Property changes on: z3reload/trunk/metadirectives.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/package-includes/z3reload-configure.zcml
===================================================================
--- z3reload/trunk/package-includes/z3reload-configure.zcml	                        (rev 0)
+++ z3reload/trunk/package-includes/z3reload-configure.zcml	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,14 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:reload="http://namespaces.pov.lt/z3reload">
+
+<include package="z3reload" />
+
+<!-- site-specific configuration -->
+
+<!-- example:
+<reload:reload
+    modules="zope.app.demo.jobboard.browser"
+    packages="zope.app.demo.hellopackage" />
+-->
+
+</configure>


Property changes on: z3reload/trunk/package-includes/z3reload-configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/package-includes/z3reload-ftesting.zcml
===================================================================
--- z3reload/trunk/package-includes/z3reload-ftesting.zcml	                        (rev 0)
+++ z3reload/trunk/package-includes/z3reload-ftesting.zcml	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1 @@
+<include package="z3reload.ftests" file="ftesting.zcml" />


Property changes on: z3reload/trunk/package-includes/z3reload-ftesting.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/package-includes/z3reload-meta.zcml
===================================================================
--- z3reload/trunk/package-includes/z3reload-meta.zcml	                        (rev 0)
+++ z3reload/trunk/package-includes/z3reload-meta.zcml	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1 @@
+<include package="z3reload" file="meta.zcml"/>


Property changes on: z3reload/trunk/package-includes/z3reload-meta.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3reload/trunk/reload.py
===================================================================
--- z3reload/trunk/reload.py	                        (rev 0)
+++ z3reload/trunk/reload.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,81 @@
+import sys
+from zope.app.pagetemplate.simpleviewclass import simple as SimplePTPage
+from zope.app.publisher.browser.viewmeta import simple as SimplePage
+
+from z3reload import BLATHER
+
+simple_view_classes = (SimplePTPage, SimplePage)
+
+
+class Reloader(object):
+    """A mixin to be used on SimpleViewClass instances.
+
+    These SimpleViewClass instances are in fact dynamically constructed types
+    with either zope.app.pagetemplate.simpleviewclass.simple or
+    zope.app.publisher,browser.viewmeta as one of the base classes.
+
+    This mixin must be the first superclass, because its __init__ must be
+    called on instantiation.
+    """
+
+    def __init__(self, *args, **kw):
+        bases = self.__class__.__bases__
+        assert len(bases) >= 2
+        reloader2, real_view = bases[:2]
+        assert reloader2 is Reloader
+
+        rest = bases[2:]
+#       for c in rest:
+#           if c not in simple_view_classes:
+#               print >> sys.stderr, "Warning: %r has base %r" % (self.__class__, c)
+
+        clsname = real_view.__name__
+        modname = real_view.__module__
+        module = sys.modules[modname]
+        if hasattr(module, clsname):
+            reload(module)
+            new_view = getattr(module, clsname)
+            self.__class__.__bases__ = (Reloader, new_view) + rest
+        else:
+            # If the module does not have such an attribute, chances are that
+            # the class was dynamically constructed.  In this case reloading is
+            # likely to break so we don't do it.
+            new_view = real_view # just use the old view
+
+        self.__sanitize_bases(new_view)
+        new_view.__init__(self, *args, **kw)
+
+    def __sanitize_bases(self, cls):
+        """Make sure that the bases of a class are in the scope.
+
+        This works around the problem when a class bases do not correspond
+        to the same-named classes in the scope, which could happen after a
+        reload.  This causes errors when invoking base clases
+        """
+        modname = cls.__module__
+        module = sys.modules[modname]
+
+        bases = cls.__bases__
+        new_bases = []
+        for b in bases:
+            bc = getattr(module, b.__name__, None)
+            if bc is not None and bc.__module__ != modname:
+                # Make sure that the base class comes from a different module.
+                new_base = getattr(module, b.__name__)
+                self.__sanitize_bases(new_base)
+                new_bases.append(new_base)
+            else:
+                # Couldn't find class in local scope, abort.
+                break
+        else:
+            # All bases checked successfully.
+            cls.__bases__ = tuple(new_bases)
+
+
+
+def install_reloader(view_class):
+    """Install the Reloader mixin on view_class."""
+    assert view_class.__bases__[-1] in simple_view_classes
+    if BLATHER:
+        print >> sys.stderr, 'Reloader installed for', view_class.__bases__[0]
+    view_class.__bases__ = (Reloader, ) + view_class.__bases__


Property changes on: z3reload/trunk/reload.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: z3reload/trunk/subscriber.py
===================================================================
--- z3reload/trunk/subscriber.py	                        (rev 0)
+++ z3reload/trunk/subscriber.py	2008-08-11 00:21:49 UTC (rev 89606)
@@ -0,0 +1,52 @@
+import sys
+
+from zope.component import getGlobalSiteManager
+from zope.publisher.interfaces import IRequest
+from zope.component.registry import AdapterRegistration
+
+from z3reload.reload import install_reloader, simple_view_classes
+from z3reload.metaconfigure import enabled_classes, enabled_modules
+from z3reload.metaconfigure import enabled_packages
+
+request_type = IRequest
+
+
+def is_simple_view(reg):
+    """Return True if reg is a registration for a `simple` view.
+
+    A `simple` view is one that subclasses one of simple_view_classes.
+    """
+    if not (isinstance(reg, AdapterRegistration) and
+            len(reg.required) > 0 and
+            reg.required[-1] is not None and
+            reg.required[-1].isOrExtends(IRequest)):
+        return False # this registration does not appear to be a view
+
+    return (type(reg.factory) == type and
+            issubclass(reg.factory, simple_view_classes))
+
+
+def reload_enabled_for(view_class):
+    """Return True if view_class should be made reloadable."""
+    assert view_class.__bases__[-1] in simple_view_classes
+    real_view = view_class.__bases__[0]
+    if real_view in enabled_classes:
+        return True
+    for module in enabled_modules:
+        if real_view.__module__ == module:
+            return True
+    for package in enabled_packages:
+        if real_view.__module__.startswith(package):
+            return True
+    return False
+
+
+def database_opened(event):
+    """Scan adapter registrations and make specified views reloadable.
+
+    Hooks on the DatabaseOpened event.
+    """
+    gsm = getGlobalSiteManager()
+    for reg in gsm.registeredAdapters():
+        if is_simple_view(reg) and reload_enabled_for(reg.factory):
+            install_reloader(reg.factory)


Property changes on: z3reload/trunk/subscriber.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native



More information about the Checkins mailing list