[Checkins] SVN: z3c.reload/trunk/ Here is a renamed, packaged and modernized version of the original

Stephan Richter srichter at cosmos.phy.tufts.edu
Mon Aug 11 02:43:08 EDT 2008


Log message for revision 89636:
  Here is a renamed, packaged and modernized version of the original 
  z3reload code.
  

Changed:
  A   z3c.reload/trunk/
  A   z3c.reload/trunk/CHANGES.txt
  A   z3c.reload/trunk/README.txt
  A   z3c.reload/trunk/bootstrap.py
  A   z3c.reload/trunk/buildout.cfg
  A   z3c.reload/trunk/setup.py
  A   z3c.reload/trunk/src/
  A   z3c.reload/trunk/src/z3c/
  A   z3c.reload/trunk/src/z3c/__init__.py
  A   z3c.reload/trunk/src/z3c/reload/
  A   z3c.reload/trunk/src/z3c/reload/README.txt
  A   z3c.reload/trunk/src/z3c/reload/__init__.py
  A   z3c.reload/trunk/src/z3c/reload/configure.zcml
  A   z3c.reload/trunk/src/z3c/reload/meta.zcml
  A   z3c.reload/trunk/src/z3c/reload/metaconfigure.py
  A   z3c.reload/trunk/src/z3c/reload/metadirectives.py
  A   z3c.reload/trunk/src/z3c/reload/reload.py
  A   z3c.reload/trunk/src/z3c/reload/subscriber.py
  A   z3c.reload/trunk/src/z3c/reload/tests/
  A   z3c.reload/trunk/src/z3c/reload/tests/__init__.py
  A   z3c.reload/trunk/src/z3c/reload/tests/application.zcml
  A   z3c.reload/trunk/src/z3c/reload/tests/dynamic.pt
  A   z3c.reload/trunk/src/z3c/reload/tests/dynamic.py
  A   z3c.reload/trunk/src/z3c/reload/tests/dynamic_orig.py
  A   z3c.reload/trunk/src/z3c/reload/tests/ftesting.zcml
  A   z3c.reload/trunk/src/z3c/reload/tests/reload.txt
  A   z3c.reload/trunk/src/z3c/reload/tests/tests.py

-=-
Added: z3c.reload/trunk/CHANGES.txt
===================================================================
--- z3c.reload/trunk/CHANGES.txt	                        (rev 0)
+++ z3c.reload/trunk/CHANGES.txt	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,8 @@
+=======
+CHANGES
+=======
+
+Version 0.1.0 (2008-08-??)
+--------------------------
+
+- Initial Release


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

Added: z3c.reload/trunk/README.txt
===================================================================
--- z3c.reload/trunk/README.txt	                        (rev 0)
+++ z3c.reload/trunk/README.txt	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,2 @@
+A package that automatically reloads view code on the fly eithout the need to
+restart a server.


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

Added: z3c.reload/trunk/bootstrap.py
===================================================================
--- z3c.reload/trunk/bootstrap.py	                        (rev 0)
+++ z3c.reload/trunk/bootstrap.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)


Property changes on: z3c.reload/trunk/bootstrap.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/buildout.cfg
===================================================================
--- z3c.reload/trunk/buildout.cfg	                        (rev 0)
+++ z3c.reload/trunk/buildout.cfg	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,24 @@
+[buildout]
+develop = .
+parts = test coverage-test coverage-report python
+index = http://download.zope.org/zope3.4
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.reload [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.reload [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[python]
+recipe = zc.recipe.egg
+interpreter = python
+eggs = z3c.reload

Added: z3c.reload/trunk/setup.py
===================================================================
--- z3c.reload/trunk/setup.py	                        (rev 0)
+++ z3c.reload/trunk/setup.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,75 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Setup
+
+$Id$
+"""
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup (
+    name='z3c.reload',
+    version='0.1.0dev',
+    author = "Gintautas Miliauskas and the Zope Community",
+    author_email = "zope3-dev at zope.org",
+    description = "Automatic View Reload",
+    long_description=(
+        read('README.txt')
+        + '\n\n' +
+        'Detailed Documentation\n'
+        '**********************'
+        + '\n\n' +
+        read('src', 'z3c', 'reload', 'README.txt')
+        + '\n\n' +
+        read('CHANGES.txt')
+        ),
+    license = "ZPL 2.1",
+    keywords = "zope3 view reload",
+    classifiers = [
+        'Development Status :: 4 - Beta',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Zope Public License',
+        'Programming Language :: Python',
+        'Natural Language :: English',
+        'Operating System :: OS Independent',
+        'Topic :: Internet :: WWW/HTTP',
+        'Framework :: Zope3'],
+    url = 'http://pypi.python.org/pypi/z3c.reload',
+    packages = find_packages('src'),
+    package_dir = {'':'src'},
+    namespace_packages = ['z3c'],
+    extras_require = dict(
+        test = ['zope.testing',
+                'zope.securitypolicy',
+                'zope.app.testing',
+                'zope.app.twisted',
+                'z3c.coverage',
+                'zc.configuration'],
+        ),
+    install_requires = [
+        'setuptools',
+        'zope.component',
+        'zope.configuration',
+        'zope.interface',
+        'zope.publisher',
+        'zope.app.pagetemplate',
+        'zope.app.publisher'
+        ],
+    include_package_data = True,
+    zip_safe = False,
+    )


Property changes on: z3c.reload/trunk/setup.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/__init__.py
===================================================================
--- z3c.reload/trunk/src/z3c/__init__.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/__init__.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,7 @@
+try:
+    # Declare this a namespace package if pkg_resources is available.
+    import pkg_resources
+    pkg_resources.declare_namespace('z3c')
+except ImportError:
+    pass
+


Property changes on: z3c.reload/trunk/src/z3c/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/README.txt
===================================================================
--- z3c.reload/trunk/src/z3c/reload/README.txt	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/README.txt	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,108 @@
+===========
+View Reload
+===========
+
+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.
+
+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:z3c="http://namespaces.zope.org/z3c">
+
+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:
+
+<z3c: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.
+
+`z3c.reload` 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
+----------------------
+
+`z3c.reload` 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.


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

Added: z3c.reload/trunk/src/z3c/reload/__init__.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/__init__.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/__init__.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,2 @@
+# Set this to True to list processed view classes on stderr.
+BLATHER = False


Property changes on: z3c.reload/trunk/src/z3c/reload/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/configure.zcml
===================================================================
--- z3c.reload/trunk/src/z3c/reload/configure.zcml	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/configure.zcml	2008-08-11 06:43:07 UTC (rev 89636)
@@ -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: z3c.reload/trunk/src/z3c/reload/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.reload/trunk/src/z3c/reload/meta.zcml
===================================================================
--- z3c.reload/trunk/src/z3c/reload/meta.zcml	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/meta.zcml	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/meta">
+
+  <directives namespace="http://namespaces.zope.org/z3c">
+    <directive
+      name="reload"
+      schema=".metadirectives.IReloadDirective"
+      handler=".metaconfigure.reload"
+      />
+  </directives>
+
+</configure>


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

Added: z3c.reload/trunk/src/z3c/reload/metaconfigure.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/metaconfigure.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/metaconfigure.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -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: z3c.reload/trunk/src/z3c/reload/metaconfigure.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/metadirectives.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/metadirectives.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/metadirectives.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,37 @@
+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.
+            """))


Property changes on: z3c.reload/trunk/src/z3c/reload/metadirectives.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/reload.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/reload.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/reload.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,78 @@
+import sys
+from zope.app.pagetemplate.simpleviewclass import simple as SimplePTPage
+from zope.app.publisher.browser.viewmeta import simple as SimplePage
+
+from z3c.reload 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:]
+
+        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: z3c.reload/trunk/src/z3c/reload/reload.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/subscriber.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/subscriber.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/subscriber.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,52 @@
+import sys
+
+from zope.component import getGlobalSiteManager
+from zope.publisher.interfaces import IRequest
+from zope.component.registry import AdapterRegistration
+
+from z3c.reload.reload import install_reloader, simple_view_classes
+from z3c.reload.metaconfigure import enabled_classes, enabled_modules
+from z3c.reload.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: z3c.reload/trunk/src/z3c/reload/subscriber.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/tests/__init__.py
===================================================================


Property changes on: z3c.reload/trunk/src/z3c/reload/tests/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/tests/application.zcml
===================================================================
--- z3c.reload/trunk/src/z3c/reload/tests/application.zcml	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/tests/application.zcml	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,47 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="demo">
+
+  <include package="zope.app.component" file="meta.zcml" />
+  <include package="zope.app.component.browser" file="meta.zcml" />
+  <include package="zope.app.form.browser" file="meta.zcml" />
+  <include package="zope.app.pagetemplate" file="meta.zcml" />
+  <include package="zope.app.publication" file="meta.zcml" />
+  <include package="zope.app.publisher" file="meta.zcml" />
+  <include package="zope.app.security" file="meta.zcml" />
+  <include package="zope.securitypolicy" file="meta.zcml" />
+  <include package="z3c.reload" file="meta.zcml" />
+  <include package="zc.configuration" file="meta.zcml" />
+
+  <exclude package="zope.app.folder.browser" />
+
+  <browser:menu id="zmi_views" title="Views" />
+  <browser:menu id="zmi_actions" title="Actions" />
+
+  <include package="zope.app.appsetup" />
+  <include package="zope.app.component" />
+  <include package="zope.app.container" />
+  <include package="zope.app.error" />
+  <include package="zope.app.folder" />
+  <include package="zope.app.i18n" />
+  <include package="zope.app.publication" />
+  <include package="zope.app.security" />
+  <include package="zope.app.session" />
+  <include package="zope.app.twisted" />
+  <include package="zope.app.wsgi" />
+  <include package="zope.annotation" />
+  <include package="zope.component" />
+  <include package="zope.location" />
+  <include package="zope.publisher" />
+  <include package="zope.securitypolicy" />
+  <include package="zope.traversing" />
+  <include package="zope.traversing.browser" />
+  <include package="z3c.reload" />
+
+  <securityPolicy
+      component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
+
+  <role id="zope.Anonymous" title="Everybody" />
+  <grantAll role="zope.Anonymous" />
+</configure>


Property changes on: z3c.reload/trunk/src/z3c/reload/tests/application.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.reload/trunk/src/z3c/reload/tests/dynamic.pt
===================================================================
--- z3c.reload/trunk/src/z3c/reload/tests/dynamic.pt	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/tests/dynamic.pt	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1 @@
+<p>The number is <span tal:replace="view/number" /></p>


Property changes on: z3c.reload/trunk/src/z3c/reload/tests/dynamic.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.reload/trunk/src/z3c/reload/tests/dynamic.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/tests/dynamic.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/tests/dynamic.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -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: z3c.reload/trunk/src/z3c/reload/tests/dynamic.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/tests/dynamic_orig.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/tests/dynamic_orig.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/tests/dynamic_orig.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -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: z3c.reload/trunk/src/z3c/reload/tests/dynamic_orig.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.reload/trunk/src/z3c/reload/tests/ftesting.zcml
===================================================================
--- z3c.reload/trunk/src/z3c/reload/tests/ftesting.zcml	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/tests/ftesting.zcml	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,26 @@
+<configure xmlns="http://namespaces.zope.org/browser"
+           xmlns:z3c="http://namespaces.zope.org/z3c"
+           package="z3c.reload.tests">
+
+  <include file="application.zcml" />
+
+  <z3c:reload modules="z3c.reload.tests.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: z3c.reload/trunk/src/z3c/reload/tests/ftesting.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.reload/trunk/src/z3c/reload/tests/reload.txt
===================================================================
--- z3c.reload/trunk/src/z3c/reload/tests/reload.txt	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/tests/reload.txt	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,68 @@
+===============
+Reloading Views
+===============
+
+
+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
+    <BLANKLINE>
+    3001
+
+
+Modification
+------------
+
+Now we will modify the view code:
+
+    >>> from z3c.reload.tests.tests import openfile
+    >>> import time
+    >>> def replace(old, new):
+    ...     time.sleep(1.0) # 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(1.0) # 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
+    <BLANKLINE>
+    3123


Property changes on: z3c.reload/trunk/src/z3c/reload/tests/reload.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.reload/trunk/src/z3c/reload/tests/tests.py
===================================================================
--- z3c.reload/trunk/src/z3c/reload/tests/tests.py	                        (rev 0)
+++ z3c.reload/trunk/src/z3c/reload/tests/tests.py	2008-08-11 06:43:07 UTC (rev 89636)
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import os
+import unittest
+from zope.testing import doctest
+from zope.app.testing import functional
+
+ReloadLayer = functional.ZCMLLayer(
+    os.path.join(os.path.split(__file__)[0], 'ftesting.zcml'),
+    __name__, 'ReloadLayer', allow_teardown=True)
+
+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)
+    suite = functional.FunctionalDocFileSuite(
+        'reload.txt',
+        setUp=resetFile, tearDown=resetFile,
+        optionflags=optionflags)
+    suite.layer = ReloadLayer
+    return unittest.TestSuite((
+        suite,
+        ))


Property changes on: z3c.reload/trunk/src/z3c/reload/tests/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the Checkins mailing list