[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