Skip to content

Commit

Permalink
Run scripts/debug console (#337)
Browse files Browse the repository at this point in the history
add zconsole module
  • Loading branch information
tschorr committed Oct 4, 2018
1 parent f4e0844 commit cb86a4f
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Expand Up @@ -19,6 +19,8 @@ Breaking changes
New features
++++++++++++

- Add zconsole module for running scripts and interactive mode.

- Restore support for XML-RPC when using the WSGI publisher - dropped in 4.0a2.

- Add a minimum ``buildout.cfg`` suggestion in the docs for creating ``wsgi``
Expand Down
17 changes: 10 additions & 7 deletions docs/operation.rst
Expand Up @@ -83,14 +83,10 @@ Debugging Zope
In order to debug the Zope application, it can be helpful to connect
to its database and inspect or change it on the command line. This
feature was previously available via the dedicated `zopectl debug`
command and the same can be achieved in the new WSGI setup.
command - in the new WSGI setup this is available via the `zconsole`
module and console script::

Assuming you have a Python interpreter with the correct sys.path
available, for example as ``bin/zopepy``, you can run::

$ ZOPE_CONFIG=etc/wsgi.conf bin/zopepy
>>> import Zope2
>>> app = Zope2.app()
$ bin/zconsole debug etc/wsgi.conf
>>> app
<Application at >

Expand All @@ -103,6 +99,13 @@ available, for example as ``bin/zopepy``, you can run::
<User 'foo'>
>>> transaction.commit()

Running scripts
---------------

This was previously availabe using `zopectl run <path_to_script> <scriparg1> ...`.
Again in the WSGI setup the `zconsole` module and console script can be used::

$ bin/zconsole run etc/wsgi.conf <path_to_script> <scriptarg1> ...

Logging In To Zope
------------------
Expand Down
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -125,6 +125,7 @@ def _read_file(filename):
'addzope2user=Zope2.utilities.adduser:main',
'runwsgi=Zope2.Startup.serve:main',
'mkwsgiinstance=Zope2.utilities.mkwsgiinstance:main',
'zconsole=Zope2.utilities.zconsole:main',
],
},
)
Empty file.
79 changes: 79 additions & 0 deletions src/Zope2/utilities/tests/test_zconsole.py
@@ -0,0 +1,79 @@
import os
import shutil
import sys
import tempfile
import unittest
from App.config import setConfiguration, getConfiguration
from six import StringIO

zope_conf_template = """
%define INSTANCE {}
instancehome $INSTANCE
<zodb_db main>
<filestorage>
path $INSTANCE/Data.fs
</filestorage>
mount-point /
</zodb_db>
"""

test_script = """
import sys
if __name__ == '__main__':
app.foo = '42'
print(app.foo)
print(sys.argv[1:])
"""


class ZConsoleTestCase(unittest.TestCase):

def setUp(self):
self.instancedir = tempfile.mkdtemp(prefix='foo42-')
self.zopeconf = os.path.join(self.instancedir, 'zope.conf')
self.stored_sys_argv = sys.argv
self.stored_stdout = sys.stdout
self.stored_app_config = getConfiguration()
with open(self.zopeconf, 'w') as conffile:
conffile.write(zope_conf_template.format(self.instancedir))

def tearDown(self):
setConfiguration(self.stored_app_config)
shutil.rmtree(self.instancedir)

def test_debug(self):
try:
from Zope2.utilities.zconsole import debug
sys.stdout = StringIO()
got = debug(self.zopeconf)
expected = '<Application at >'
finally:
sys.argv = self.stored_sys_argv
sys.stdout = self.stored_stdout
self.assertEqual(expected, str(got))

def test_runscript(self):
script = os.path.join(self.instancedir, 'test_script.py')
with open(script, 'w') as scriptfile:
scriptfile.write(test_script)
try:
from Zope2.utilities.zconsole import runscript
sys.argv = [
sys.executable,
'run',
self.zopeconf,
script,
'bar', 'baz']
sys.stdout = StringIO()
runscript(self.zopeconf, script, 'bar', 'baz')
sys.stdout.seek(0)
got = sys.stdout.read()
finally:
sys.argv = self.stored_sys_argv
sys.stdout = self.stored_stdout
expected = "42\n['run', '{}', '{}', 'bar', 'baz']\n".format(self.zopeconf, script) # noqa: E501
self.assertEqual(expected, got)
52 changes: 52 additions & 0 deletions src/Zope2/utilities/zconsole.py
@@ -0,0 +1,52 @@
import os
import sys
import Zope2
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SpecialUsers import system as user
from Testing.makerequest import makerequest
from Zope2.Startup.run import make_wsgi_app
from zope.globalrequest import setRequest


def runscript(zopeconf, script_name, *extra_args):
make_wsgi_app({}, zopeconf)
app = Zope2.app()
app = makerequest(app)
app.REQUEST['PARENTS'] = [app]
setRequest(app.REQUEST)
newSecurityManager(None, user)
scriptglobals = globals()
scriptglobals.update(__name__='__main__')
with open(script_name) as script:
scriptcode = script.read()
exec(compile(scriptcode, script_name, 'exec'))


def debug(zopeconf):
make_wsgi_app({}, zopeconf)
return Zope2.app()


def debug_console(zopeconf):
cmd = '{} -i -c "import sys; sys.path={}; from Zope2.utilities.zconsole import debug; app = debug(\\\"{}\\\")"'.format(sys.executable, sys.path, zopeconf) # noqa: E501
os.system(cmd)


def main(args=sys.argv):
import argparse
parser = argparse.ArgumentParser(description='Zope console')
parser.add_argument(
'mode',
choices=['run', 'debug'],
help='mode of operation, run: run script; debug: interactive console') # noqa: E501
parser.add_argument('zopeconf', help='path to zope.conf')
parser.add_argument('scriptargs', nargs=argparse.REMAINDER)
namespace, unused = parser.parse_known_args(args[1:])
if namespace.mode == 'debug':
debug_console(namespace.zopeconf)
elif namespace.mode == 'run':
runscript(namespace.zopeconf, *namespace.scriptargs)


if __name__ == '__main__':
main()

0 comments on commit cb86a4f

Please sign in to comment.