[Checkins] SVN: grokcore.startup/trunk/ svn merge ipython-debug-shell
Jan Wijbrand Kolman
cvs-admin at zope.org
Tue May 1 14:27:43 UTC 2012
Log message for revision 125497:
svn merge ipython-debug-shell
Changed:
U grokcore.startup/trunk/CHANGES.txt
U grokcore.startup/trunk/buildout.cfg
U grokcore.startup/trunk/setup.py
U grokcore.startup/trunk/src/grokcore/startup/README.txt
U grokcore.startup/trunk/src/grokcore/startup/__init__.py
A grokcore.startup/trunk/src/grokcore/startup/debug.py
U grokcore.startup/trunk/src/grokcore/startup/startup.py
-=-
Modified: grokcore.startup/trunk/CHANGES.txt
===================================================================
--- grokcore.startup/trunk/CHANGES.txt 2012-05-01 14:23:02 UTC (rev 125496)
+++ grokcore.startup/trunk/CHANGES.txt 2012-05-01 14:27:40 UTC (rev 125497)
@@ -4,9 +4,10 @@
1.2 (unreleased)
================
-- Nothing changed yet.
+- Added new IPython-based interactive debugger which is used
+ automatically when IPython is available. Otherwise the gdb-style
+ debugger is provided.
-
1.1 (2010-10-26)
================
Modified: grokcore.startup/trunk/buildout.cfg
===================================================================
--- grokcore.startup/trunk/buildout.cfg 2012-05-01 14:23:02 UTC (rev 125496)
+++ grokcore.startup/trunk/buildout.cfg 2012-05-01 14:27:40 UTC (rev 125497)
@@ -17,5 +17,5 @@
[test]
recipe = zc.recipe.testrunner
-eggs = grokcore.startup
+eggs = grokcore.startup [test]
defaults = ['--tests-pattern', '^f?tests$', '-v']
Modified: grokcore.startup/trunk/setup.py
===================================================================
--- grokcore.startup/trunk/setup.py 2012-05-01 14:23:02 UTC (rev 125496)
+++ grokcore.startup/trunk/setup.py 2012-05-01 14:27:40 UTC (rev 125497)
@@ -18,8 +18,13 @@
'zope.interface',
'zope.testing',
'zope.security',
+ 'zope.securitypolicy',
]
+debug_requires = [
+ 'IPython',
+ ]
+
setup(
name='grokcore.startup',
version='1.2dev',
@@ -50,7 +55,7 @@
'zope.app.debug',
],
tests_require = tests_require,
- extras_require = dict(test=tests_require),
+ extras_require = dict(test=tests_require, debug=debug_requires),
entry_points={
'paste.app_factory': [
'main = grokcore.startup:application_factory',
Modified: grokcore.startup/trunk/src/grokcore/startup/README.txt
===================================================================
--- grokcore.startup/trunk/src/grokcore/startup/README.txt 2012-05-01 14:23:02 UTC (rev 125496)
+++ grokcore.startup/trunk/src/grokcore/startup/README.txt 2012-05-01 14:27:40 UTC (rev 125497)
@@ -260,11 +260,34 @@
>>> import shutil
>>> shutil.rmtree(temp_dir)
-``interactive_debug_prompt(zope_conf_path)``
+``get_debugger(zope_conf_path)``
--------------------------------------------
Get an interactive console with a debugging shell started.
+ `grokcore.startup` provides two different debuggers currently: a
+ plain one based on `zope.app.debug` and a more powerful `IPython`_
+ debugger. The IPython debugger is automatically enabled if you have
+ IPython available in the environment.
+
+ You can explicitly enable the IPython_ debugger by stating::
+
+ grokcore.startup [debug]
+
+ in the install requirements of your `setup.py`, probably adding only
+ ``[debug]`` to an already existing entry for
+ `grokcore.startup`. Don't forget to rerun `buildout` afterwards.
+
+ You can explicitly require one or the other debugger by calling::
+
+ grokcore.startup.startup.interactive_debug_prompt(zope_conf)
+
+ or::
+
+ grokcore.startup.debug.ipython_debug_prompt(zope_conf)
+
+ in the ``[interactive_debugger]`` section of your ``buildout.cfg``.
+
>>> import zope.app.appsetup.appsetup
>>> # Ugh - allow a reconfiguration of an app.
>>> zope.app.appsetup.appsetup._configured = False
@@ -313,7 +336,7 @@
... pprint(__file__)
... pprint(__name__)""")
>>>
- >>> sys.argv = ['interactive_debug_prompt', script]
+ >>> sys.argv = ['get_debugger', script]
>>> from grokcore.startup import interactive_debug_prompt
>>> try:
... interactive_debug_prompt(zope_conf=zopeconf)
@@ -347,3 +370,4 @@
.. _WSGI: http://www.wsgi.org/wsgi/
.. _WSGIPublisherApplication: http://apidoc.zope.org/++apidoc++/Code/zope/app/wsgi/WSGIPublisherApplication/index.html
.. _zc.buildout: http://pypi.python.org/pypi/zc.buildout
+.. _ipython: http://ipython.org/
Modified: grokcore.startup/trunk/src/grokcore/startup/__init__.py
===================================================================
--- grokcore.startup/trunk/src/grokcore/startup/__init__.py 2012-05-01 14:23:02 UTC (rev 125496)
+++ grokcore.startup/trunk/src/grokcore/startup/__init__.py 2012-05-01 14:27:40 UTC (rev 125497)
@@ -12,6 +12,8 @@
#
##############################################################################
# Make this a package.
-from grokcore.startup.startup import (application_factory,
- debug_application_factory,
- interactive_debug_prompt)
+from grokcore.startup.startup import (
+ application_factory,
+ debug_application_factory,
+ interactive_debug_prompt,
+ )
Copied: grokcore.startup/trunk/src/grokcore/startup/debug.py (from rev 125496, grokcore.startup/branches/ipython-debug-shell/src/grokcore/startup/debug.py)
===================================================================
--- grokcore.startup/trunk/src/grokcore/startup/debug.py (rev 0)
+++ grokcore.startup/trunk/src/grokcore/startup/debug.py 2012-05-01 14:27:40 UTC (rev 125497)
@@ -0,0 +1,209 @@
+##############################################################################
+#
+# Copyright (c) 2006-2012 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.
+#
+##############################################################################
+import sys
+import os.path
+import textwrap
+
+import transaction
+import zope.app.wsgi
+import zope.app.debug
+from pprint import pprint
+from zope.securitypolicy.zopepolicy import settingsForObject
+from zope.component import getUtility, getMultiAdapter
+
+from IPython.frontend.terminal.embed import InteractiveShellEmbed
+shell = InteractiveShellEmbed()
+
+
+PATH_SEP = '/'
+
+class GrokDebug(object):
+
+ def __init__(self, zope_conf='parts/etc/zope.debug.conf'):
+ db = zope.app.wsgi.config(zope_conf)
+ debugger = zope.app.debug.Debugger.fromDatabase(db)
+ self.app = debugger
+ self.root = debugger.root()
+ self.context = self.root
+
+ def get_start_context(self, path):
+ if path.startswith(PATH_SEP):
+ context = self.root
+ else:
+ # relative path
+ context = self.context
+ return context
+
+ def _get_object_names(self, context):
+ return [obj.__name__ for obj in context.values()]
+
+ def ns(self):
+ """Return namespace dictionary.
+
+ To be used for updating namespace of commands available
+ for user in shell.
+ """
+ return dict(lsg=self.ls,
+ cdg=self.cd,
+ pwdg=self.pwd,
+ app=self.app,
+ root=self.root,
+ ctx=self.ctx,
+ sec=self.get_security_settings,
+ gu=getUtility,
+ gma=getMultiAdapter,
+ sync=self.sync,
+ pby=self.providedBy,
+ commit=transaction.commit)
+
+ def update_ns(self):
+ shell.user_ns.update(self.ns())
+
+ def get_security_settings(self, path):
+ pprint(settingsForObject(get_context_by_path(
+ self.get_start_context(path), path)))
+
+ def sync(self):
+ self.root._p_jar.sync()
+
+ def ls(self, path=None):
+ """List objects.
+
+ This command is bound to `lsg` in IPython shell.
+
+ Without `path` parameter list objects in current container,
+ which is available as `ctx` from IPython shell.
+
+ `path` can be relative or absolute.
+
+ To use autocompletion of path command should be invoked
+ with prepended semicolon in ipython shell as
+ ;lsg /path
+ """
+ if path is None:
+ return self._get_object_names(self.context)
+
+ context = get_context_by_path(self.get_start_context(path), path)
+ return self._get_object_names(context)
+
+
+ def cd(self, path):
+ """cd to specified path.
+
+ Bound to `cdg` in IPython shell.
+ `path` can be relative or absolute.
+
+ To use autocompletion of path command should be invoked
+ with prepended semicolon in ipython shell as
+ ;cdg /path
+ """
+ if path.strip() == '..':
+ self.context = self.context.__parent__
+ self.update_ns()
+ return self.pwd
+
+ # cd
+ self.context = get_context_by_path(self.get_start_context(path), path)
+ self.update_ns()
+ return self.pwd
+
+ @property
+ def pwd(self):
+ """Print absolute path to current context object.
+
+ Bound to `pwdg` in IPython shell
+ """
+ res = []
+ obj = self.context
+ while obj is not None:
+ name = obj.__name__
+ if name is not None and name:
+ res.append(name)
+ obj = obj.__parent__
+
+ if not res:
+ return PATH_SEP
+
+ res = PATH_SEP.join(reversed(res))
+ if not res.startswith(PATH_SEP):
+ return PATH_SEP + res
+
+ return res
+
+ @property
+ def ctx(self):
+ """Return current context object.
+
+ Bound to `ctx` in IPython shell
+ """
+ return self.context
+
+ def providedBy(self, obj=None):
+ if not obj:
+ obj = self.ctx
+ return list(zope.interface.providedBy(obj))
+
+def get_context_by_path(context, path):
+ for name in (p for p in path.split(PATH_SEP) if p):
+ context = context[name]
+ return context
+
+def path_completer(self, event):
+ """TAB path completer for `cdg` and `lsg` commands."""
+ relpath = event.symbol
+
+ context = grokd.get_start_context(relpath)
+
+ # ends with '/'
+ if relpath.endswith(PATH_SEP):
+ context = get_context_by_path(context, relpath)
+ return [relpath+obj.__name__ for obj in context.values()]
+
+ head, tail = os.path.split(relpath)
+ if head and not head.endswith(PATH_SEP):
+ head += PATH_SEP
+ context = get_context_by_path(context, head)
+
+ return [head+obj.__name__ for obj in context.values()
+ if obj.__name__.startswith(tail)]
+
+
+def ipython_debug_prompt(zope_conf):
+ grokd = GrokDebug(zope_conf)
+ banner = textwrap.dedent(
+ """\
+ IPython shell for Grok.
+
+ Bound object names:
+ -------------------
+ root
+ ctx
+
+ Bound command names:
+ --------------------
+ cdg / ;cdg
+ lsg / ;lsg
+ sec / ;sec
+ gu / ;gu
+ gma / ;gma
+ pby (providedBy)
+ pwdg
+ sync
+ commit
+ """)
+
+ shell.user_ns.update(grokd.ns())
+ shell.banner2=banner
+ shell.set_hook('complete_command', path_completer, re_key='.*cdg|.*lsg')
+ shell(local_ns=grokd.ns())
Modified: grokcore.startup/trunk/src/grokcore/startup/startup.py
===================================================================
--- grokcore.startup/trunk/src/grokcore/startup/startup.py 2012-05-01 14:23:02 UTC (rev 125496)
+++ grokcore.startup/trunk/src/grokcore/startup/startup.py 2012-05-01 14:27:40 UTC (rev 125497)
@@ -32,9 +32,7 @@
# Return the created application
return app
-def interactive_debug_prompt(
- zope_conf=os.path.join('parts', 'etc', 'zope.conf')):
-
+def _classic_debug_prompt(zope_conf):
db = zope.app.wsgi.config(zope_conf)
debugger = zope.app.debug.Debugger.fromDatabase(db)
globals_ = {
@@ -67,3 +65,14 @@
"The 'app' variable contains the Debugger, 'app.publish(path)' "
"simulates a request.")
code.interact(banner=banner, local=globals_)
+
+def _ipython_debug_prompt(zope_conf):
+ from grokcore.startup.debug import ipython_debug_prompt
+ return ipython_debug_prompt(zope_conf)
+
+def interactive_debug_prompt(zope_conf):
+ try:
+ import IPython
+ except ImportError:
+ return _classic_debug_prompt(zope_conf)
+ return _ipython_debug_prompt(zope_conf)
More information about the checkins
mailing list