[Checkins] SVN: Sandbox/cklinger/megrok.reload/ Initial Import of megrok.reload

Christian Klinger cklinger at novareto.de
Fri Feb 19 03:49:07 EST 2010


Log message for revision 109139:
  Initial Import of megrok.reload

Changed:
  A   Sandbox/cklinger/megrok.reload/
  A   Sandbox/cklinger/megrok.reload/trunk/
  A   Sandbox/cklinger/megrok.reload/trunk/HISTORY.txt
  A   Sandbox/cklinger/megrok.reload/trunk/README.txt
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/__init__.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/__init__.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/browser.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/code.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/config.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/configure.zcml
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/fivezcml.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/interfaces.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/templates/
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/templates/reload.pt
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/xreload.py
  A   Sandbox/cklinger/megrok.reload/trunk/megrok/reload/zcml.py
  A   Sandbox/cklinger/megrok.reload/trunk/setup.py

-=-
Added: Sandbox/cklinger/megrok.reload/trunk/HISTORY.txt
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/HISTORY.txt	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/HISTORY.txt	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,7 @@
+Changelog
+=========
+
+alldev (unreleased)
+-------------------
+
+- Initial release

Added: Sandbox/cklinger/megrok.reload/trunk/README.txt
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/README.txt	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/README.txt	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,4 @@
+Introduction
+============
+
+

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/__init__.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/__init__.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/__init__.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/__init__.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/__init__.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/__init__.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1 @@
+#

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/browser.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/browser.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/browser.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,56 @@
+import grok
+
+from zope.interface import Interface
+from megrok.reload.code import reload_code
+from megrok.reload.interfaces import IReload
+from megrok.reload.zcml import reload_zcml
+
+grok.templatedir('templates')
+
+class Reload(grok.View):
+    """Reload view.
+    """
+    grok.context(Interface)
+    grok.implements(IReload)
+    message = None
+
+    def update(self):
+        action = self.request.form.get('action')
+        if action is not None:
+            if action == 'code':
+                self.message = self.code_reload()
+            elif action == 'zcml':
+                self.message = self.zcml_reload()
+
+    def status(self):
+        return self.message
+
+    def code_reload(self):
+        reloaded = reload_code()
+
+        result = ''
+        if reloaded:
+            result += 'Code reloaded:\n\n'
+            result += '\n'.join(reloaded)
+        else:
+            result = 'No code reloaded!'
+        return result
+
+    def zcml_reload(self):
+
+        # We always do an implicit code reload so we can register all newly
+        # added classes.
+        reloaded = reload_code()
+        reload_zcml()
+
+        # TODO Minimize all caches, we only really want to invalidate the
+        # local site manager from all caches
+        # aq_base(self.context)._p_jar.db().cacheMinimize() BBB
+        result = ''
+        if reloaded:
+            result += 'Code reloaded:\n\n'
+            result += '\n'.join(reloaded)
+        else:
+            result = 'No code reloaded!'
+        result += '\n\nGlobal ZCML reloaded.'
+        return result

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/code.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/code.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/code.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,95 @@
+import grok
+import os
+import sys
+
+from os.path import abspath
+from os.path import isfile
+
+from megrok.reload import config
+from megrok.reload.xreload import Reloader
+
+_marker = object()
+MOD_TIMES = dict()
+
+
+def in_search_path(path):
+    if 'site-packages' in path:
+        return False
+    elif '.egg' in path:
+        return False
+    return True
+
+
+def search_modules():
+    modules = []
+    for name, module in sys.modules.items():
+        if module is not None:
+            f = getattr(module, '__file__', None)
+            # Standard library modules don't have a __file__
+            if f is None:
+                continue
+            f = abspath(f)
+            if config.EXCLUDE_SITE_PACKAGES:
+                if in_search_path(f):
+                    modules.append((f, module))
+            else:
+                modules.append((f, module))
+    return modules
+
+
+def get_mod_time(path):
+    mtime = 0
+    # If we have the compiled source, look for the source code change date
+    if path.endswith('pyc') or path.endswith('pyo'):
+        source = path[:-1]
+        if os.path.isfile(source):
+            path = source
+    # protect against missing and unaccessible files
+    if isfile(path):
+        mtime = os.stat(path)[8]
+    return mtime
+
+
+import zope.processlifetime
+#@grok.subscribe(zope.processlifetime.IProcessStarting)
+ at grok.subscribe(zope.processlifetime.IDatabaseOpened)  #BBB ASK Hanno if this could be a problem
+def get_mod_times(event=None):
+    global MOD_TIMES
+    for path, module in search_modules():
+        if path not in MOD_TIMES:
+            MOD_TIMES[path] = (get_mod_time(path), module)
+    return MOD_TIMES
+
+
+def check_mod_times():
+    changed = []
+    for path, (time, module) in get_mod_times().items():
+        newtime = get_mod_time(path)
+        if time < newtime:
+            changed.append((path, newtime, module))
+    return changed
+
+
+def reload_code():
+    global MOD_TIMES
+    reloaded = []
+    for path, time, module in check_mod_times():
+        r = Reloader(module)
+        module = r.reload()
+        MOD_TIMES[path] = (time, module)
+        reloaded.append(path)
+    return reloaded
+
+
+# Before Zope 2.12 there was no event for process startup. We therefor hook
+# ourselves into the last function called during the startup procedure. In
+# 2.12 the logging setup was moved up in the startup logic, so our monkey
+# patch was only applied after the function had already been called.
+
+
+def setup_mod_times(func):
+    def init_times(*args, **kwargs):
+        get_mod_times()
+        return func(*args, **kwargs)
+    return init_times
+

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/config.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/config.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/config.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1 @@
+EXCLUDE_SITE_PACKAGES = True

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/configure.zcml
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/configure.zcml	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/configure.zcml	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,16 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:browser="http://namespaces.zope.org/browser"
+           xmlns:grok="http://namespaces.zope.org/grok"
+           xmlns:zcml="http://namespaces.zope.org/zcml">
+
+    <include package="grok"/>
+    <grok:grok package="."/>
+
+
+<!--
+  <subscriber
+    zcml:condition="installed zope.processlifetime"
+    for="zope.processlifetime.IProcessStarting"
+    handler="plone.reload.code.get_mod_times" />
+-->
+</configure>

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/fivezcml.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/fivezcml.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/fivezcml.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# Copyright (c) 2004, 2005 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.
+#
+##############################################################################
+"""ZCML machinery
+
+$Id: zcml.py 96815 2009-02-20 13:25:03Z hannosch $
+"""
+import os
+import os.path
+from zope.configuration import xmlconfig
+
+_initialized = False
+_context = None
+
+
+def load_site():
+    """Load a Five/Zope site by finding and loading the appropriate site
+    configuration file."""
+    global _initialized
+    if _initialized:
+        return
+    _initialized = True
+
+    import Globals
+    Globals.INSTANCE_HOME
+
+    # load instance site configuration file
+    site_zcml = os.path.join(Globals.INSTANCE_HOME, "etc", "site.zcml")
+
+    import Zope2.utilities
+    zope_utilities = os.path.dirname(Zope2.utilities.__file__)
+    skel_site_zcml = os.path.join(zope_utilities, "skel", "etc", "site.zcml")
+    
+    if os.path.exists(site_zcml):
+        file = site_zcml
+    else:
+        # check for zope installation home skel during running unit tests
+        file = skel_site_zcml
+
+    global _context
+    _context = xmlconfig.file(file)
+
+
+def load_config(file, package=None, execute=True):
+    """Load an additional ZCML file into the context.
+
+    Use with extreme care.
+    """
+    global _context
+    _context = xmlconfig.file(file, package, _context, execute=execute)
+
+def load_string(s):
+    """Load a snipped of ZCML into the context.
+
+    Use with extreme care.
+    """
+    global _context
+    _context = xmlconfig.string(s, _context)
+
+# clean up code
+
+def cleanUp():
+    global _context
+    _context = None
+
+from zope.testing.cleanup import addCleanUp
+addCleanUp(cleanUp)
+del addCleanUp

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/interfaces.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/interfaces.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/interfaces.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,15 @@
+from zope.interface import Interface
+
+
+class IReload(Interface):
+    """Interface for the ZCML reload view.
+    """
+
+    def status():
+        """Return a status text."""
+
+    def code_reload():
+        """Reload all changed code."""
+
+    def zcml_reload():
+        """Reprocess all global ZCML."""

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/templates/reload.pt
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/templates/reload.pt	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/templates/reload.pt	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+      xmlns:tal="http://xml.zope.org/namespaces/tal">
+<head>
+  <title>plone.reload</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+
+    <h1>plone.reload</h1>
+
+    <tal:block tal:condition="view/status">
+
+        <h2>Status</h2>
+
+        <pre tal:content="view/status"
+             style="background-color:#ddd; padding:0.5em;
+                    border: 1px black dashed; line-height:1.2em;">
+            Status
+        </pre>
+
+    </tal:block>
+
+    <h2>Actions</h2>
+
+    <table>
+        <tr>
+            <td style="padding:3px;">
+                <form action="#"
+                      method="get"
+                      tal:attributes="action request/getURL">
+
+                    <input type="hidden" name="action" value="code" />
+
+                    <input type="submit" value="Reload Code" />
+
+                </form>
+            </td>
+            <td style="padding:3px;">
+                <form action="#"
+                      method="get"
+                      tal:attributes="action request/getURL">
+
+                    <input type="hidden" name="action" value="zcml" />
+
+                    <input type="submit" value="Reload Code and ZCML" />
+
+                </form>
+            </td>
+        </tr>
+    </table>
+
+</body>
+</html>

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/xreload.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/xreload.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/xreload.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,218 @@
+# xreload.py.
+
+"""Alternative to reload().
+
+This works by executing the module in a scratch namespace, and then
+patching classes, methods and functions. This avoids the need to
+patch instances. New objects are copied into the target namespace.
+
+Taken and extended from xreload as posted by Guido van Rossum:
+
+    http://mail.python.org/pipermail/edu-sig/2007-February/007787.html
+
+"""
+
+import marshal
+import imp
+import sys
+import types
+import inspect
+
+import zope.component
+
+
+class ClosureChanged(Exception):
+    pass
+
+
+class Reloader(object):
+    """Reload a module in place, updating classes, methods and functions.
+
+    Args:
+      mod: a module object
+
+    Returns:
+      The (updated) input object itself.
+    """
+
+    def __init__(self, module):
+        self.mod = module
+
+    def reload(self):
+        # Get the module name, e.g. 'foo.bar.whatever'
+        modname = self.mod.__name__
+
+        # Get the module namespace (dict) early; this is part of the type check
+        modns = self.mod.__dict__
+        # Parse it into package name and module name, e.g. 'foo.bar' and 
+        # 'whatever'
+        i = modname.rfind(".")
+        if i >= 0:
+            pkgname, modname = modname[:i], modname[i+1:]
+        else:
+            pkgname = None
+        # Compute the search path
+        if pkgname:
+            # We're not reloading the package, only the module in it
+            pkg = sys.modules[pkgname]
+            path = pkg.__path__  # Search inside the package
+        else:
+            # Search the top-level module path
+            pkg  = None
+            path = None  # Make find_module() uses the default search path
+        # Find the module; may raise ImportError
+        (stream, filename, (suffix, mode, kind)) = imp.find_module(modname, path)
+        # Turn it into a code object
+        try:
+            # Is it Python source code or byte code read from a file?
+            # XXX Could handle frozen modules, zip-import modules
+            if kind not in (imp.PY_COMPILED, imp.PY_SOURCE):
+                # Fall back to built-in reload()
+                return reload(self.mod)
+            if kind == imp.PY_SOURCE:
+                source = stream.read()
+                # PeterB: if we don't strip the source code and add newline we get 
+                # a SyntaxError even if `python $filename` is perfectly happy.
+                source = source.strip()+'\n'
+                code = compile(source, filename, "exec")
+            else:
+                # I have no idea how to test this one
+                code = marshal.load(stream) #pragma NO COVER
+        finally:
+            if stream:
+                stream.close()
+        # Execute the code im a temporary namespace; if this fails, no changes
+        tmpns = {'__name__': '%s.%s' % (pkgname, modname),
+                 '__file__': filename,
+                 '__doc__': modns['__doc__']}
+        exec(code, tmpns)
+        # Now we get to the hard part
+        _update_scope(modns, tmpns)
+        # Now update the rest in place
+        for name in set(modns) & set(tmpns):
+            modns[name] = self._update(modns[name], tmpns[name])
+        # Done!
+        return self.mod
+
+    def _update(self, oldobj, newobj):
+        """Update oldobj, if possible in place, with newobj.
+
+        If oldobj is immutable, this simply returns newobj.
+
+        Args:
+          oldobj: the object to be updated
+          newobj: the object used as the source for the update
+
+        Returns:
+          either oldobj, updated in place, or newobj.
+        """
+        if type(oldobj) is not type(newobj):
+            # Cop-out: if the type changed, give up
+            return newobj
+
+        new_module = getattr(newobj, '__module__', None)
+        if new_module != self.mod.__name__:
+            # Do not update objects in-place that have been imported.
+            # Just update their references.
+            return newobj
+
+        if isinstance(newobj, zope.interface.interface.Specification):
+            # XXX we can't update interfaces because their internal
+            # data structures break. We'll have to implement the reload method
+            # for those and patch it in.
+           return oldobj
+        if inspect.isclass(newobj):
+            return _update_class(oldobj, newobj)
+        elif inspect.isfunction(newobj):
+            return _update_function(oldobj, newobj)
+
+        # XXX Support class methods, static methods, other decorators
+        # Not something we recognize, just give up
+        # This line is currently not hit at all, since we only call this on
+        # a module. It's pretty hard to have a non-function, non-class entity
+        # in a module, which has a __module__ pointer to the module itself
+        return newobj #pragma NO COVER
+
+
+def _closure_changed(oldcl, newcl):
+    old = oldcl is None and -1 or len(oldcl)
+    new = newcl is None and -1 or len(newcl)
+    if old != new:
+        return True
+    if old > 0 and new > 0:
+        for i in range(old):
+            same = oldcl[i] == newcl[i]
+            if not same:
+                return True
+    return False
+
+
+def _update_scope(oldscope, newscope):
+    oldnames = set(oldscope)
+    newnames = set(newscope)
+    # Add newly introduced names
+    for name in newnames - oldnames:
+        oldscope[name] = newscope[name]
+    # Delete names that are no longer current
+    for name in oldnames - newnames:
+        if not name.startswith('__'):
+            del oldscope[name]
+
+
+def _update_function(oldfunc, newfunc):
+    """Update a function object."""
+    if _closure_changed(oldfunc.func_closure, newfunc.func_closure):
+        raise ClosureChanged
+    oldfunc.func_code = newfunc.func_code
+    oldfunc.func_defaults = newfunc.func_defaults
+    _update_scope(oldfunc.func_globals, newfunc.func_globals)
+    # XXX What else?
+    return oldfunc
+
+
+def _update_method(oldmeth, newmeth):
+    """Update a method object."""
+    # XXX What if im_func is not a function?
+    _update_function(oldmeth.im_func, newmeth.im_func)
+    return oldmeth
+
+
+def _update_class(oldclass, newclass):
+    """Update a class object."""
+    # XXX What about __slots__?
+    olddict = oldclass.__dict__
+    newdict = newclass.__dict__
+    oldnames = set(olddict)
+    newnames = set(newdict)
+    for name in newnames - oldnames:
+        setattr(oldclass, name, newdict[name])
+
+    # Note: We do not delete attributes, because various ZCML directives,
+    # grokkers and other wiring add class attributes during startup that
+    # would get lost if we did this. Note that attributes will still be
+    # overwritten if they've changed.
+    # 
+    # for name in oldnames - newnames:
+    #     delattr(oldclass, name)
+
+    for name in oldnames & newnames - set(["__dict__", "__doc__"]):
+        try:
+            new = getattr(newclass, name)
+            old = getattr(oldclass, name, None)
+            if isinstance(new, types.MethodType):
+                if isinstance(old, property) and not isinstance(new, property):
+                    # Removing a decorator
+                    setattr(oldclass, name, new.im_func)
+                else:
+                    _update_method(old, new)
+            elif isinstance(new, types.FunctionType):
+                # __init__ is a function
+                _update_function(old, new)
+            else:
+                # Fallback to just replace the item
+                setattr(oldclass, name, new)
+        except ClosureChanged:
+            # If the closure changed, we need to replace the entire function
+            setattr(oldclass, name, new.im_func)
+
+    return oldclass

Added: Sandbox/cklinger/megrok.reload/trunk/megrok/reload/zcml.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/megrok/reload/zcml.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/megrok/reload/zcml.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,63 @@
+try:
+    from zope.site.hooks import setSite
+except ImportError:
+    from zope.app.component.hooks import setSite
+
+from zope.component import getGlobalSiteManager
+from zope.testing import cleanup
+
+import fivezcml
+
+CORE_CLEANUPS = frozenset([
+    'zope.app.apidoc.classregistry',
+    'zope.app.component.hooks',
+    'zope.app.security.principalregistry',
+    'zope.app.schema.vocabulary',
+    'zope.component.globalregistry',
+    'zope.schema.vocabulary',
+    'zope.security.management',
+    'zope.security.checker',
+    'zope.site.hooks',
+])
+
+
+def cleanups():
+    registered = [c[0] for c in cleanup._cleanups]
+    functions = []
+    for r in registered:
+        if r.__module__ not in CORE_CLEANUPS:
+            functions.append(r)
+    return functions
+
+import martian
+def reload_zcml():
+    #from grokcore.component.zcml import 
+
+    def resetBootstrap():
+        # we need to make sure that the grokker registry is clean again
+        the_module_grokker.clear()
+    from zope.testing.cleanup import addCleanUp
+    addCleanUp(resetBootstrap)
+
+    the_multi_grokker = martian.MetaMultiGrokker()
+    the_module_grokker = martian.ModuleGrokker(the_multi_grokker)
+
+    return
+    gsm = getGlobalSiteManager()
+    old_gsm_dict = gsm.__dict__.copy()
+    try:
+        setSite(None)
+        gsm.__init__(gsm.__name__)
+        # Clean up
+        for clean in cleanups():
+            clean()
+        # Reload all ZCML
+        import pdb;pdb.set_trace()
+        fivezcml._initialized = False
+        fivezcml._context._seen_files.clear()
+        fivezcml.load_site()
+    except Exception, e:
+        gsm.__init__(gsm.__name__)
+        gsm.__dict__.clear()
+        gsm.__dict__.update(old_gsm_dict)
+        raise e

Added: Sandbox/cklinger/megrok.reload/trunk/setup.py
===================================================================
--- Sandbox/cklinger/megrok.reload/trunk/setup.py	                        (rev 0)
+++ Sandbox/cklinger/megrok.reload/trunk/setup.py	2010-02-19 08:49:06 UTC (rev 109139)
@@ -0,0 +1,32 @@
+from setuptools import setup, find_packages
+import os
+
+version = 'all'
+
+setup(name='megrok.reload',
+      version=version,
+      description="extension which reloads code and zcml without restarting the server",
+      long_description=open("README.txt").read() + "\n" +
+                       open(os.path.join("docs", "HISTORY.txt")).read(),
+      # Get more strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      classifiers=[
+        "Programming Language :: Python",
+        ],
+      keywords='',
+      author='',
+      author_email='',
+      url='http://svn.plone.org/svn/collective/',
+      license='GPL',
+      packages=find_packages(exclude=['ez_setup']),
+      namespace_packages=['megrok'],
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=[
+          'setuptools',
+          'grok',
+          # -*- Extra requirements: -*-
+      ],
+      entry_points="""
+      # -*- Entry points: -*-
+      """,
+      )



More information about the checkins mailing list