From fijal at codespeak.net Wed Nov 1 15:32:49 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Wed, 1 Nov 2006 15:32:49 +0100 (CET)
Subject: [py-svn] r34030 - py/dist/py/apigen/tracer/testing
Message-ID: <20061101143249.3113010077@code0.codespeak.net>
Author: fijal
Date: Wed Nov 1 15:32:48 2006
New Revision: 34030
Modified:
py/dist/py/apigen/tracer/testing/test_model.py
Log:
(stakkars, fijal) - Fixed order.
Modified: py/dist/py/apigen/tracer/testing/test_model.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_model.py (original)
+++ py/dist/py/apigen/tracer/testing/test_model.py Wed Nov 1 15:32:48 2006
@@ -105,8 +105,8 @@
pass
g = guess_type(A).unionof(guess_type(A()))
- l = list(g.striter())
- assert l[0] == "AnyOf("
- assert isinstance(l[1], SomeClass)
- assert l[2] == ", "
- assert isinstance(l[3], SomeInstance)
+ l = sorted(list(g.striter()))
+ assert l[4] == "AnyOf("
+ assert isinstance(l[0], SomeClass)
+ assert l[3] == ", "
+ assert isinstance(l[1], SomeInstance)
From fijal at codespeak.net Fri Nov 3 11:38:48 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Fri, 3 Nov 2006 11:38:48 +0100 (CET)
Subject: [py-svn] r34089 - in py/dist/py/apigen: rest tracer tracer/testing
Message-ID: <20061103103848.2B5091005A@code0.codespeak.net>
Author: fijal
Date: Fri Nov 3 11:38:47 2006
New Revision: 34089
Modified:
py/dist/py/apigen/rest/genrest.py
py/dist/py/apigen/tracer/description.py
py/dist/py/apigen/tracer/testing/test_docgen.py
Log:
(guido, fijal) - Intermediate checkin of somehow changing semantics of __dict__ monitoring.
Modified: py/dist/py/apigen/rest/genrest.py
==============================================================================
--- py/dist/py/apigen/rest/genrest.py (original)
+++ py/dist/py/apigen/rest/genrest.py Fri Nov 3 11:38:47 2006
@@ -390,7 +390,10 @@
tbrest.append(Paragraph(Link(linkname, linktarget)))
else:
tbrest.append(Paragraph(linkname))
- source = line.code.source()
+ try:
+ source = line.code.source()
+ except IOError:
+ source = "*Cannot get source*"
mangled = []
for i, sline in enumerate(str(source).split('\n')):
if i == lineno:
Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py (original)
+++ py/dist/py/apigen/tracer/description.py Fri Nov 3 11:38:47 2006
@@ -4,6 +4,7 @@
import types
import inspect
+import copy
MAX_CALL_SITES = 20
@@ -42,9 +43,6 @@
def __cmp__(self, other):
return cmp(self._getval(), other._getval())
-class NoValue(object):
- """used in MethodDesc.get_local_changes() when there is no value"""
-
def cut_stack(stack, frame, upward_frame=None):
if hasattr(frame, 'raw'):
frame = frame.raw
@@ -234,7 +232,7 @@
def __init__(self, *args, **kwargs):
super(MethodDesc, self).__init__(*args, **kwargs)
self.old_dict = {}
- self.new_dict = {}
+ self.changeset = {}
# right now it's not different than method desc, only code is different
def getcode(self):
@@ -245,28 +243,47 @@
def consider_start_locals(self, frame):
# XXX recursion issues?
- obj = frame.f_locals.get('self')
- if not obj:
- # static method
+ obj = frame.f_locals[self.pyobj.im_func.func_code.co_varnames[0]]
+ try:
+ if not obj:
+ # static method
+ return
+ except AttributeError:
return
- self.old_dict = obj.__dict__.copy()
+ #self.old_dict = self.perform_dict_copy(obj.__dict__)
+ self.old_dict = copy.deepcopy(obj.__dict__)
def consider_end_locals(self, frame):
- obj = frame.f_locals.get('self')
- if not obj:
- # static method
+ obj = frame.f_locals[self.pyobj.im_func.func_code.co_varnames[0]]
+ try:
+ if not obj:
+ # static method
+ return
+ except AttributeError:
return
- self.new_dict = obj.__dict__.copy()
+ # store the local changes
+ # update self.changeset
+ self.update_changeset(obj.__dict__)
def get_local_changes(self):
- changeset = {}
+ return self.changeset
+
+ def set_changeset(changeset, key, value):
+ if key not in changeset:
+ changeset[key] = set([value])
+ else:
+ changeset[key].add(value)
+ set_changeset = staticmethod(set_changeset)
+
+ def update_changeset(self, new_dict):
+ changeset = self.changeset
for k, v in self.old_dict.iteritems():
- if k not in self.new_dict:
- changeset[k] = (v, NoValue)
- elif self.new_dict[k] != v:
- changeset[k] = (v, self.new_dict[k])
- for k, v in self.new_dict.iteritems():
+ if k not in new_dict:
+ self.set_changeset(changeset, k, "deleted")
+ elif new_dict[k] != v:
+ self.set_changeset(changeset, k, "changed")
+ for k, v in new_dict.iteritems():
if k not in self.old_dict:
- changeset[k] = (NoValue, v)
+ self.set_changeset(changeset, k, "created")
return changeset
Modified: py/dist/py/apigen/tracer/testing/test_docgen.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_docgen.py (original)
+++ py/dist/py/apigen/tracer/testing/test_docgen.py Fri Nov 3 11:38:47 2006
@@ -160,8 +160,8 @@
t.end_tracing()
desc = ds.descs['testclass']
methdesc = desc.fields['bar']
- assert methdesc.old_dict != methdesc.new_dict
- assert methdesc.get_local_changes() == {'foo': (0, 1)}
+ #assert methdesc.old_dict != methdesc.new_dict
+ assert methdesc.get_local_changes() == {'foo': set(['changed'])}
def test_local_changes_nochange():
class testclass(object):
@@ -177,4 +177,3 @@
desc = ds.descs['testclass']
methdesc = desc.fields['bar']
assert methdesc.get_local_changes() == {}
-
From guido at codespeak.net Fri Nov 3 14:08:18 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Fri, 3 Nov 2006 14:08:18 +0100 (CET)
Subject: [py-svn] r34097 - in py/dist/py/apigen: rest tracer
Message-ID: <20061103130818.92CC010079@code0.codespeak.net>
Author: guido
Date: Fri Nov 3 14:08:16 2006
New Revision: 34097
Modified:
py/dist/py/apigen/rest/genrest.py
py/dist/py/apigen/tracer/description.py
Log:
Fixed problems with deepcopy() not being able to copy everything, adjusted
genrest to cope with the changes in tracer.
Modified: py/dist/py/apigen/rest/genrest.py
==============================================================================
--- py/dist/py/apigen/rest/genrest.py (original)
+++ py/dist/py/apigen/rest/genrest.py Fri Nov 3 14:08:16 2006
@@ -332,14 +332,8 @@
local_changes = self.dsa.get_function_local_changes(functionname)
lst.append(Paragraph('Changes in __dict__:'))
- from py.__.apigen.tracer.description import NoValue
- for k, (oldvalue, newvalue) in local_changes.iteritems():
- description = 'value changed'
- if oldvalue is NoValue:
- description = 'newly added'
- elif newvalue is NoValue:
- description = 'deleted'
- lst.append(ListItem('%s: %s' % (k, description)))
+ for k, changeset in local_changes.iteritems():
+ lst.append(ListItem('%s: %s' % (k, ', '.join(changeset))))
# XXX missing implementation of dsa.get_function_location()
#filename, lineno = self.dsa.get_function_location(functionname)
Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py (original)
+++ py/dist/py/apigen/tracer/description.py Fri Nov 3 14:08:16 2006
@@ -250,8 +250,19 @@
return
except AttributeError:
return
- #self.old_dict = self.perform_dict_copy(obj.__dict__)
- self.old_dict = copy.deepcopy(obj.__dict__)
+ self.old_dict = self.perform_dict_copy(obj.__dict__)
+
+ def perform_dict_copy(self, d):
+ try:
+ c = copy.deepcopy(d)
+ except:
+ c = {}
+ for k, v in d.iteritems():
+ try:
+ c[k] = copy.deepcopy(v)
+ except:
+ c[k] = v
+ return c
def consider_end_locals(self, frame):
obj = frame.f_locals[self.pyobj.im_func.func_code.co_varnames[0]]
From arigo at codespeak.net Sun Nov 5 12:31:14 2006
From: arigo at codespeak.net (arigo at codespeak.net)
Date: Sun, 5 Nov 2006 12:31:14 +0100 (CET)
Subject: [py-svn] r34227 - in py/dist/py/test: . rsession
Message-ID: <20061105113114.4478F10084@code0.codespeak.net>
Author: arigo
Date: Sun Nov 5 12:31:05 2006
New Revision: 34227
Modified:
py/dist/py/test/cmdline.py
py/dist/py/test/rsession/box.py
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/slave.py
Log:
(fijal, arigo)
Kill some imports and dead code.
Modified: py/dist/py/test/cmdline.py
==============================================================================
--- py/dist/py/test/cmdline.py (original)
+++ py/dist/py/test/cmdline.py Sun Nov 5 12:31:05 2006
@@ -4,8 +4,6 @@
# main entry point
#
-from py.__.test.rsession.rsession import AbstractSession
-
def main(args=None):
warn_about_missing_assertion()
if args is None:
@@ -17,12 +15,16 @@
session = sessionclass(config)
# ok, some option checks
- if config.option.startserver and not isinstance(session, AbstractSession):
- print "Cannot use web server without (R|L)Session"
- raise SystemExit, 2
- if config.option.apigen and not isinstance(session, AbstractSession):
- print "Cannot generate API without (R|L)Session"
- raise SystemExit, 2
+ if config.option.startserver:
+ from py.__.test.rsession.rsession import AbstractSession
+ if not isinstance(session, AbstractSession):
+ print "Cannot use web server without (R|L)Session"
+ raise SystemExit, 2
+ if config.option.apigen:
+ from py.__.test.rsession.rsession import AbstractSession
+ if not isinstance(session, AbstractSession):
+ print "Cannot generate API without (R|L)Session"
+ raise SystemExit, 2
if config.option.runbrowser and not config.option.startserver:
print "Cannot point browser when not starting server"
raise SystemExit, 2
Modified: py/dist/py/test/rsession/box.py
==============================================================================
--- py/dist/py/test/rsession/box.py (original)
+++ py/dist/py/test/rsession/box.py Sun Nov 5 12:31:05 2006
@@ -7,7 +7,6 @@
import os
import sys
import marshal
-import thread
NICE_LEVEL = 0 # XXX make it a conftest option
@@ -36,101 +35,6 @@
self.exitstat = 0
return 123
-class FifoBox(object):
- def __init__(self, fun, args = [], kwargs = {}):
- self.fun = fun
- self.args = args
- self.kwargs = kwargs
-
- def run(self):
- dirname = tempfile.mkdtemp("pytest")
- self.dirname = dirname
- self.PYTESTRETVAL = os.path.join(dirname, PYTESTRETVAL)
- self.PYTESTSTDERR = os.path.join(dirname, PYTESTSTDERR)
- self.PYTESTSTDOUT = os.path.join(dirname, PYTESTSTDOUT)
- os.mkfifo(self.PYTESTSTDOUT)
- os.mkfifo(self.PYTESTSTDERR)
- os.mkfifo(self.PYTESTRETVAL)
- pid = os.fork()
- if pid:
- self.parent()
- else:
- try:
- outcome = self.children()
- except:
- excinfo = py.code.ExceptionInfo()
- print "Internal box error"
- for i in excinfo.traceback:
- print str(i)[2:-1]
- print excinfo
- os._exit(1)
- os.close(1)
- os.close(2)
- os._exit(0)
- return pid
-
- def children(self):
- # right now we need to call a function, but first we need to
- # map all IO that might happen
- # make sure sys.stdout points to file descriptor one
- fdstdout = os.open(self.PYTESTSTDOUT, os.O_WRONLY)
- if fdstdout != 1:
- os.dup2(fdstdout, 1)
- fdstderr = os.open(self.PYTESTSTDERR, os.O_WRONLY)
- if fdstderr != 2:
- os.dup2(fdstderr, 2)
- sys.stdout = os.fdopen(1, "w", 0)
- sys.stderr = os.fdopen(2, "w", 0)
- retvalf = open(self.PYTESTRETVAL, "w")
- if NICE_LEVEL:
- os.nice(NICE_LEVEL)
- retval = self.fun(*self.args, **self.kwargs)
- retvalf.write(marshal.dumps(retval))
- retvalf.close()
-
- def parent(self):
- stdoutlock = thread.allocate_lock()
- stdoutlock.acquire()
- stderrlock = thread.allocate_lock()
- stderrlock.acquire()
-
- def readsome(name, field, lock):
- fd = open(name, "r")
- setattr(self, field, fd.read())
- fd.close()
- lock.release()
-
- thread.start_new_thread(readsome, (self.PYTESTSTDOUT, 'stdoutrepr', stdoutlock))
- thread.start_new_thread(readsome, (self.PYTESTSTDERR, 'stderrrepr', stderrlock))
-
- retval = open(self.PYTESTRETVAL, "r")
- pid, exitstat = os.wait()
- self.signal = exitstat & 0x7f
- self.exitstat = exitstat & 0xff00
-
- if not exitstat:
- retval_data = retval.read()
- self.retval = marshal.loads(retval_data)
- retval.close()
- else:
- self.retval = None
-
- stdoutlock.acquire()
- stdoutlock.release()
- stderrlock.acquire()
- stderrlock.release()
-
- self.clear()
- return self.stdoutrepr, self.stderrrepr
-
- def clear(self):
- try:
- os.unlink(self.PYTESTSTDOUT)
- os.unlink(self.PYTESTSTDERR)
- os.unlink(self.PYTESTRETVAL)
- os.rmdir(self.dirname)
- except OSError:
- pass
class FileBox(object):
count = 0
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Sun Nov 5 12:31:05 2006
@@ -4,8 +4,6 @@
import os
import py
-import thread
-import threading
import sys
import re
import time
Modified: py/dist/py/test/rsession/slave.py
==============================================================================
--- py/dist/py/test/rsession/slave.py (original)
+++ py/dist/py/test/rsession/slave.py Sun Nov 5 12:31:05 2006
@@ -56,14 +56,6 @@
else:
send(res)
-def setup_screen():
- # We cannot easily just assume that we do have full communication
- # channels, so we have to provide a new ones.
- import thread
- import os, sys
- # the idea is simple: we create another process in which we perform
- # read/write operations on both channels
-
def setup():
default_options = {'nomagic':False} # XXX should come from somewhere else
From arigo at codespeak.net Sun Nov 5 16:05:00 2006
From: arigo at codespeak.net (arigo at codespeak.net)
Date: Sun, 5 Nov 2006 16:05:00 +0100 (CET)
Subject: [py-svn] r34242 - py/dist/py/c-extension/greenlet
Message-ID: <20061105150500.BB28210082@code0.codespeak.net>
Author: arigo
Date: Sun Nov 5 16:04:58 2006
New Revision: 34242
Modified:
py/dist/py/c-extension/greenlet/greenlet.c
Log:
(tismer, arigo)
A greenlet bug, as shown by an assert. On Linux the bug silently does
nothing, but on Windows we get a crash.
Modified: py/dist/py/c-extension/greenlet/greenlet.c
==============================================================================
--- py/dist/py/c-extension/greenlet/greenlet.c (original)
+++ py/dist/py/c-extension/greenlet/greenlet.c Sun Nov 5 16:04:58 2006
@@ -177,6 +177,7 @@
*/
long sz1 = g->stack_saved;
long sz2 = stop - g->stack_start;
+ assert(g->stack_start != NULL);
if (sz2 > sz1) {
char* c = PyMem_Realloc(g->stack_copy, sz2);
if (!c) {
@@ -378,7 +379,10 @@
/* start the greenlet */
ts_target->stack_start = NULL;
ts_target->stack_stop = (char*) mark;
- ts_target->stack_prev = ts_current;
+ if (ts_current->stack_start == NULL) /* ts_current is dying */
+ ts_target->stack_prev = ts_current->stack_prev;
+ else
+ ts_target->stack_prev = ts_current;
ts_target->top_frame = NULL;
ts_target->recursion_depth = PyThreadState_GET()->recursion_depth;
err = _PyGreen_switchstack();
From mwh at codespeak.net Sun Nov 5 16:38:12 2006
From: mwh at codespeak.net (mwh at codespeak.net)
Date: Sun, 5 Nov 2006 16:38:12 +0100 (CET)
Subject: [py-svn] r34244 - in py/dist/py: . documentation xmlobj
xmlobj/testing
Message-ID: <20061105153812.EE4A41007C@code0.codespeak.net>
Author: mwh
Date: Sun Nov 5 16:38:10 2006
New Revision: 34244
Modified:
py/dist/py/__init__.py
py/dist/py/documentation/confrest.py
py/dist/py/xmlobj/testing/test_xml.py
py/dist/py/xmlobj/visit.py
py/dist/py/xmlobj/xml.py
Log:
add a py.xml.raw() object that can include html/xml directly in a py.xml.Tag()
(i.e. without any escaping).
use this in confrest.Project.process, which will hopefully unbreak
http://codespeak.net/py/current/doc/
(my first py lib checkin, i think :-)
(guido: this was your fault)
Modified: py/dist/py/__init__.py
==============================================================================
--- py/dist/py/__init__.py (original)
+++ py/dist/py/__init__.py Sun Nov 5 16:38:10 2006
@@ -109,6 +109,7 @@
# small and mean xml/html generation
'xml.html' : ('./xmlobj/html.py', 'html'),
'xml.Tag' : ('./xmlobj/xml.py', 'Tag'),
+ 'xml.raw' : ('./xmlobj/xml.py', 'raw'),
'xml.Namespace' : ('./xmlobj/xml.py', 'Namespace'),
'xml.escape' : ('./xmlobj/misc.py', 'escape'),
Modified: py/dist/py/documentation/confrest.py
==============================================================================
--- py/dist/py/documentation/confrest.py (original)
+++ py/dist/py/documentation/confrest.py Sun Nov 5 16:38:10 2006
@@ -116,7 +116,7 @@
html.div(html.div(modified, style="float: right; font-style: italic;"),
id = 'docinfoline'))
- page.contentspace.append(content)
+ page.contentspace.append(py.xml.raw(content))
htmlpath = txtpath.new(ext='.html')
htmlpath.write(page.unicode().encode(encoding))
Modified: py/dist/py/xmlobj/testing/test_xml.py
==============================================================================
--- py/dist/py/xmlobj/testing/test_xml.py (original)
+++ py/dist/py/xmlobj/testing/test_xml.py Sun Nov 5 16:38:10 2006
@@ -51,3 +51,7 @@
u = unicode(x)
assert u == ''
+def test_raw():
+ x = ns.some(py.xml.raw("
literal
"))
+ u = unicode(x)
+ assert u == "literal
"
Modified: py/dist/py/xmlobj/visit.py
==============================================================================
--- py/dist/py/xmlobj/visit.py (original)
+++ py/dist/py/xmlobj/visit.py Sun Nov 5 16:38:10 2006
@@ -34,6 +34,9 @@
#self.write(obj)
self.write(escape(unicode(obj)))
+ def raw(self, obj):
+ self.write(obj.uniobj)
+
def list(self, obj):
assert id(obj) not in self.visited
self.visited[id(obj)] = 1
Modified: py/dist/py/xmlobj/xml.py
==============================================================================
--- py/dist/py/xmlobj/xml.py (original)
+++ py/dist/py/xmlobj/xml.py Sun Nov 5 16:38:10 2006
@@ -24,6 +24,12 @@
name = self.__class__.__name__
return "<%r tag object %d>" % (name, id(self))
+class raw(object):
+ """just a box that can contain a unicode string that will be
+ included directly in the output"""
+ def __init__(self, uniobj):
+ self.uniobj = uniobj
+
# the generic xml namespace
# provides Tag classes on the fly optionally checking for
# a tagspecification
From fijal at codespeak.net Thu Nov 9 15:19:39 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Thu, 9 Nov 2006 15:19:39 +0100 (CET)
Subject: [py-svn] r34413 - py/dist/py/test
Message-ID: <20061109141939.9501C10070@code0.codespeak.net>
Author: fijal
Date: Thu Nov 9 15:19:35 2006
New Revision: 34413
Modified:
py/dist/py/test/config.py
Log:
Improved caching of configs.
Modified: py/dist/py/test/config.py
==============================================================================
--- py/dist/py/test/config.py (original)
+++ py/dist/py/test/config.py Thu Nov 9 15:19:35 2006
@@ -172,19 +172,26 @@
Config._reset()
return config
+_config_paths_cache = {}
def guessconfigpaths(*paths):
""" return test configuration paths from skimming the args. """
+ key = tuple(paths)
+ try:
+ return _config_paths_cache[key]
+ except KeyError:
+ pass
d = {}
l = []
- for anchor in paths:
- if anchor:
+ for anchor in paths:
+ if anchor:
for p in anchor.parts():
x = p.join(configbasename)
if x not in d and x.check(file=1):
d[x] = True
l.append(x)
l.reverse()
+ _config_paths_cache[key] = l
return l
def getanchorpaths(args):
@@ -199,7 +206,7 @@
l = [current]
return l
-def importconfig(configpath):
+def importconfig(configpath):
if not configpath.dirpath('__init__.py').check(file=1):
# HACK: we don't want a "globally" imported conftest.py,
# prone to conflicts and subtle problems
From fijal at codespeak.net Thu Nov 9 15:20:09 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Thu, 9 Nov 2006 15:20:09 +0100 (CET)
Subject: [py-svn] r34414 - py/dist/py/path/local
Message-ID: <20061109142009.73A8710070@code0.codespeak.net>
Author: fijal
Date: Thu Nov 9 15:20:05 2006
New Revision: 34414
Modified:
py/dist/py/path/local/local.py
Log:
Make pyimport cache modules. This speeds up py.test --collectonly about 3 times.
Modified: py/dist/py/path/local/local.py
==============================================================================
--- py/dist/py/path/local/local.py (original)
+++ py/dist/py/path/local/local.py Thu Nov 9 15:20:05 2006
@@ -19,6 +19,8 @@
""" Local path implementation offering access/modification
methods similar to os.path.
"""
+ _path_cache = {}
+
sep = os.sep
class Checkers(common.FSCheckers):
def _stat(self):
@@ -53,6 +55,10 @@
Note also that passing in a local path object will simply return
the exact same path object. Use new() to get a new copy.
"""
+ #try:
+ # return cls._path_cache[path]
+ #except KeyError:
+ # pass
if isinstance(path, common.FSPathBase):
if path.__class__ == cls:
return path
@@ -68,6 +74,7 @@
"can only pass None, Path instances "
"or non-empty strings to LocalPath")
assert isinstance(self.strpath, str)
+ #cls._path_cache[path] = self
return self
def __hash__(self):
@@ -120,7 +127,7 @@
obj.strpath = os.path.normpath(
"%(drive)s%(dirname)s%(sep)s%(basename)s" % kw)
return obj
-
+
def _getbyspec(self, spec):
""" return a sequence of specified path parts. 'spec' is
a comma separated string containing path part names.
@@ -374,6 +381,11 @@
#print "trying to import", self
pkgpath = None
if modname is None:
+ if modname is None:
+ try:
+ return self.module
+ except AttributeError:
+ pass
pkgpath = self.pypkgpath()
if pkgpath is not None:
if ensuresyspath:
@@ -394,7 +406,9 @@
if ensuresyspath:
self._prependsyspath(self.dirpath())
modname = self.purebasename
- return __import__(modname, None, None, ['__doc__'])
+ mod = __import__(modname, None, None, ['__doc__'])
+ self.module = mod
+ return mod
else:
try:
return sys.modules[modname]
From fijal at codespeak.net Thu Nov 9 15:25:39 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Thu, 9 Nov 2006 15:25:39 +0100 (CET)
Subject: [py-svn] r34415 - py/dist/py/path/local
Message-ID: <20061109142539.7399B10050@code0.codespeak.net>
Author: fijal
Date: Thu Nov 9 15:25:34 2006
New Revision: 34415
Modified:
py/dist/py/path/local/local.py
Log:
Removed debug code (commented anyway).
Modified: py/dist/py/path/local/local.py
==============================================================================
--- py/dist/py/path/local/local.py (original)
+++ py/dist/py/path/local/local.py Thu Nov 9 15:25:34 2006
@@ -55,10 +55,6 @@
Note also that passing in a local path object will simply return
the exact same path object. Use new() to get a new copy.
"""
- #try:
- # return cls._path_cache[path]
- #except KeyError:
- # pass
if isinstance(path, common.FSPathBase):
if path.__class__ == cls:
return path
@@ -74,7 +70,6 @@
"can only pass None, Path instances "
"or non-empty strings to LocalPath")
assert isinstance(self.strpath, str)
- #cls._path_cache[path] = self
return self
def __hash__(self):
From fijal at codespeak.net Thu Nov 9 16:36:10 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Thu, 9 Nov 2006 16:36:10 +0100 (CET)
Subject: [py-svn] r34418 - in py/dist/py/test/rsession: . testing
Message-ID: <20061109153610.781761008D@code0.codespeak.net>
Author: fijal
Date: Thu Nov 9 16:36:07 2006
New Revision: 34418
Modified:
py/dist/py/test/rsession/conftest.py
py/dist/py/test/rsession/hostmanage.py
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/testing/test_rsession.py
Log:
Refactored hostmanage a bit, fixing the tests, so they don't need to be run over Ssh.
Modified: py/dist/py/test/rsession/conftest.py
==============================================================================
--- py/dist/py/test/rsession/conftest.py (original)
+++ py/dist/py/test/rsession/conftest.py Thu Nov 9 16:36:07 2006
@@ -4,9 +4,9 @@
defaultwait = 100.0
option = py.test.Config.addoptions("distributed testing options",
- Option('-D', '--disthosts',
- action="store", dest="disthosts", default=None,
- help="comma separated list of testhosts"),
+# Option('-D', '--disthosts',
+# action="store", dest="disthosts", default=None,
+# help="comma separated list of testhosts"),
Option('', '--waittime',
action="store", dest="waittime", default=defaultwait,
help="How long (in seconds) to wait for hanging nodes"
Modified: py/dist/py/test/rsession/hostmanage.py
==============================================================================
--- py/dist/py/test/rsession/hostmanage.py (original)
+++ py/dist/py/test/rsession/hostmanage.py Thu Nov 9 16:36:07 2006
@@ -27,24 +27,10 @@
else:
return base in self.rsync_roots
-
-def init_hosts(reporter, sshhosts, relpath, pkgdir, rsync_roots=None, \
- remote_python=None, remote_options={}):
- assert pkgdir.join("__init__.py").check(), (
- "%s probably wrong" %(pkgdir,))
- assert relpath, relpath
-
- nodes = []
- exc_info = [None]
+def prepare_gateway(sshosts, relpath, rsync_roots, optimise_localhost, remote_python):
hosts = []
-
- for host in sshhosts:
-
- if host != 'localhost':
- if remote_python is None:
- gw = py.execnet.SshGateway(host)
- else:
- gw = py.execnet.SshGateway(host, remotepython=remote_python)
+ for host in sshosts:
+ if host != 'localhost' or not optimise_localhost:
if isinstance(relpath, str):
assert not os.path.isabs(relpath), relpath
remoterootpath = relpath
@@ -53,7 +39,18 @@
# XXX: because of NFS we do create different directories
# otherwise, .pyc files overlap
remoterootpath += "-" + host
-
+ # for tests we want to use somtehing different
+ if host == 'localhost' and optimise_localhost is False:
+ from py.__.execnet.register import PopenCmdGateway
+ gw = PopenCmdGateway("cd ~/%s; python -u -c 'exec input()'" % remoterootpath)
+ if not remoterootpath.startswith("/"):
+ remoteroopath = "~/" + remoterootpath
+ else:
+ if remote_python is None:
+ gw = py.execnet.SshGateway(host)
+ else:
+ gw = py.execnet.SshGateway(host, remotepython=remote_python)
+
hosts.append((host, gw, remoterootpath))
else:
if remote_python is None:
@@ -62,9 +59,24 @@
gw = py.execnet.PopenGateway(remotepython=remote_python)
gw.sshaddress = 'localhost'
hosts.append((host, gw, str(pkgdir.dirpath())))
+ return hosts
+def init_hosts(reporter, sshhosts, relpath, pkgdir, rsync_roots=None, \
+ remote_python=None, remote_options={}, optimise_localhost=True):
+ assert pkgdir.join("__init__.py").check(), (
+ "%s probably wrong" %(pkgdir,))
+ assert relpath, relpath
+
+ nodes = []
+ exc_info = [None]
+ hosts = prepare_gateway(sshhosts, relpath, rsync_roots, optimise_localhost,
+ remote_python)
+
# rsyncing
- rsynced = {'localhost':True}
+ if optimise_localhost:
+ rsynced = {'localhost':True}
+ else:
+ rsynced = {}
rsync = HostRSync(rsync_roots)
for host, gw, remoterootpath in hosts:
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Thu Nov 9 16:36:07 2006
@@ -36,8 +36,9 @@
An abstract session executes collectors/items through a runner.
"""
- def __init__(self, config):
+ def __init__(self, config, optimise_localhost=True):
self.config = config
+ self.optimise_localhost = optimise_localhost
def make_colitems(paths, baseon):
# we presume that from the base we can simply get to
@@ -139,7 +140,8 @@
remote_options['nomagic'] = self.config.option.nomagic
nodes = init_hosts(reporter, sshhosts, directories, pkgdir,
- rsync_roots, remotepython, remote_options=remote_options.d)
+ rsync_roots, remotepython, remote_options=remote_options.d,
+ optimise_localhost=self.optimise_localhost)
reporter(report.RsyncFinished())
keyword = self.config.option.keyword
Modified: py/dist/py/test/rsession/testing/test_rsession.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rsession.py (original)
+++ py/dist/py/test/rsession/testing/test_rsession.py Thu Nov 9 16:36:07 2006
@@ -69,11 +69,11 @@
assert str(events[1][0].value) == "Reason"
class TestWithRealSshHosts:
- def setup_class(cls):
- from py.__.test.rsession.conftest import option
- if not option.disthosts:
- py.test.skip("no test distribution ssh hosts specified")
- cls.hosts = option.disthosts.split(",")
+ #def setup_class(cls):
+ # from py.__.test.rsession.conftest import option
+ # if not option.disthosts:
+ # py.test.skip("no test distribution ssh hosts specified")
+ # cls.hosts = option.disthosts.split(",")
## def test_rsync_does_what_it_should(self):
## host = self.hosts[0]
@@ -112,9 +112,9 @@
# XXX find a better way for the below
tmpdir = py.path.local(py.__file__).dirpath().dirpath()
tmpdir.ensure("sub", "conftest.py").write(py.code.Source("""
- disthosts = %r
+ disthosts = [%r]
distrsync_roots = ["sub", "py"]
- """ % self.hosts[:1]))
+ """ % 'localhost'))
tmpdir.ensure("sub", "__init__.py")
tmpdir.ensure("sub", "test_one.py").write(py.code.Source("""
def test_1():
@@ -128,7 +128,7 @@
"""))
args = [str(tmpdir.join("sub"))]
config, args = py.test.Config.parse(args)
- rsession = RSession(config)
+ rsession = RSession(config, optimise_localhost=False)
allevents = []
rsession.main(args, reporter=allevents.append)
testevents = [x for x in allevents
@@ -154,21 +154,21 @@
assert tb[0].source.find("execute") != -1
def test_setup_teardown_ssh(self):
- hosts = self.hosts
+ hosts = ['localhost']
setup_events = []
teardown_events = []
nodes = init_hosts(setup_events.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"])
+ rsync_roots=["py"], optimise_localhost=False)
teardown_hosts(teardown_events.append,
[node.channel for node in nodes], nodes)
count_rsyn_calls = [i for i in setup_events
if isinstance(i, report.HostRSyncing)]
- assert len(count_rsyn_calls) == len([i for i in hosts if i != 'localhost'])
+ assert len(count_rsyn_calls) == len([i for i in hosts])
count_ready_calls = [i for i in setup_events
if isinstance(i, report.HostReady)]
- assert len(count_ready_calls) == len([i for i in hosts if i != 'localhost'])
+ assert len(count_ready_calls) == len([i for i in hosts])
# same for teardown events
teardown_wait_starts = [i for i in teardown_events
@@ -179,11 +179,11 @@
assert len(teardown_wait_ends) == len(hosts)
def test_setup_teardown_run_ssh(self):
- hosts = self.hosts
+ hosts = ['localhost']
allevents = []
nodes = init_hosts(allevents.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"])
+ rsync_roots=["py"], optimise_localhost=False)
from py.__.test.rsession.testing.test_executor \
import ItemTestPassing, ItemTestFailing, ItemTestSkipping
@@ -220,9 +220,10 @@
""" Tests options object passing master -> server
"""
allevents = []
- hosts = self.hosts
+ hosts = ['localhost']
nodes = init_hosts(allevents.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"], remote_options={'custom':'custom'})
+ rsync_roots=["py"], remote_options={'custom':'custom'},
+ optimise_localhost=False)
rootcol = py.test.collect.Directory(pkgdir.dirpath())
itempass = rootcol.getitembynames(funcoption_spec)
From fijal at codespeak.net Thu Nov 9 17:24:40 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Thu, 9 Nov 2006 17:24:40 +0100 (CET)
Subject: [py-svn] r34424 - in py/dist/py/test/rsession: . testing
Message-ID: <20061109162440.5D80D10094@code0.codespeak.net>
Author: fijal
Date: Thu Nov 9 17:24:38 2006
New Revision: 34424
Modified:
py/dist/py/test/rsession/reporter.py
py/dist/py/test/rsession/testing/test_reporter.py
Log:
Reporter tests refactoring. Now FailedTryiter works for both reporters (and is tested)
Modified: py/dist/py/test/rsession/reporter.py
==============================================================================
--- py/dist/py/test/rsession/reporter.py (original)
+++ py/dist/py/test/rsession/reporter.py Thu Nov 9 17:24:38 2006
@@ -11,6 +11,7 @@
from py.__.test.terminal.out import getout
from py.__.test.rsession import report
+from py.__.test.rsession import outcome
class AbstractReporter(object):
def __init__(self, config, hosts, pkgdir=py.path.local(py.__file__)):
@@ -75,7 +76,8 @@
self.timeend = item.timeend
self.skips()
self.failures()
- self.hangs()
+ if hasattr(self, 'nodes'): # XXX: Testing
+ self.hangs()
self.summary()
def hangs(self):
@@ -91,13 +93,18 @@
if self.failed_tests_outcome:
self.out.sep("=", " FAILURES ")
for event in self.failed_tests_outcome:
- host = self.get_host(event)
- self.out.sep('_', "%s on %s" %
- (" ".join(event.item.listnames()), host))
- if event.outcome.signal:
- self.repr_signal(event.item, event.outcome)
+ if isinstance(event, report.ReceivedItemOutcome):
+ host = self.get_host(event)
+ self.out.sep('_', "%s on %s" %
+ (" ".join(event.item.listnames()), host))
+ if event.outcome.signal:
+ self.repr_signal(event.item, event.outcome)
+ else:
+ self.repr_failure(event.item, event.outcome)
else:
- self.repr_failure(event.item, event.outcome)
+ self.out.sep('_', " ".join(event.item.listnames()))
+ out = outcome.Outcome(excinfo=event.excinfo)
+ self.repr_failure(event.item, outcome.ReprOutcome(out.make_repr()))
def repr_failure(self, item, outcome):
excinfo = outcome.excinfo
@@ -221,14 +228,18 @@
class RemoteReporter(AbstractReporter):
def get_host(self, item):
- return item.channel.gateway.sshaddress
+ if item.channel:
+ return item.channel.gateway.sshaddress
+ # XXX: Testing purposes only
+ return 'localhost'
def get_item_name(self, event, colitem):
- return event.channel.gateway.sshaddress + ":" + \
+ return self.get_host(event) + ":" + \
"/".join(colitem.listnames())
-
+
def report_FailedTryiter(self, event):
self.out.line("FAILED TO LOAD MODULE: %s\n" % "/".join(event.item.listnames()))
+ self.failed_tests_outcome.append(event)
def report_SkippedTryiter(self, event):
self.out.line("Skipped (%s) %s\n" % (str(event.excinfo.value), "/".
@@ -248,6 +259,7 @@
def report_FailedTryiter(self, event):
#self.show_item(event.item, False)
self.out.write("- FAILED TO LOAD MODULE")
+ self.failed_tests_outcome.append(event)
def report_ReceivedItemOutcome(self, event):
if event.outcome.passed:
Modified: py/dist/py/test/rsession/testing/test_reporter.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_reporter.py (original)
+++ py/dist/py/test/rsession/testing/test_reporter.py Thu Nov 9 17:24:38 2006
@@ -4,8 +4,9 @@
"""
import py, os
-from py.__.test.rsession.rsession import LocalReporter, AbstractSession
-from py.__.test.rsession.report import ReceivedItemOutcome, ItemStart
+from py.__.test.rsession.rsession import LocalReporter, AbstractSession,\
+ RemoteReporter
+from py.__.test.rsession import report
from py.__.test.rsession.outcome import ReprOutcome, Outcome
from py.__.test.rsession.testing.test_slave import funcpass_spec, mod_spec
from py.__.test.rsession.box import Box
@@ -16,7 +17,7 @@
def setup_module(mod):
mod.pkgdir = py.path.local(py.__file__).dirpath()
-class TestReporter(object):
+class AbstractTestReporter(object):
def prepare_outcomes(self):
# possible outcomes
try:
@@ -35,7 +36,7 @@
return outcomes
- def test_report_received_item_outcome(self):
+ def report_received_item_outcome(self):
config, args = py.test.Config.parse(["some_sub"])
# we just go...
rootcol = py.test.collect.Directory(pkgdir.dirpath())
@@ -43,19 +44,19 @@
outcomes = self.prepare_outcomes()
def boxfun(config, item, outcomes):
- r = LocalReporter(config, ["localhost"])
+ r = self.reporter(config, ["localhost"])
for outcome in outcomes:
- r.report(ReceivedItemOutcome(None, item, outcome))
+ r.report(report.ReceivedItemOutcome(None, item, outcome))
s = StringIO()
stdoutcopy = sys.stdout
sys.stdout = s
boxfun(config, item, outcomes)
- sys.stdoud = stdoutcopy
+ sys.stdout = stdoutcopy
- assert s.getvalue() == 'FsF.'
+ return s.getvalue()
- def test_module(self):
+ def _test_module(self):
config, args = py.test.Config.parse(["some_sub"])
# we just go...
rootcol = py.test.collect.Directory(pkgdir.dirpath())
@@ -64,22 +65,22 @@
outcomes = self.prepare_outcomes()
def boxfun(pkgdir, config, item, funcitem, outcomes):
- r = LocalReporter(config, ["localhost"])
+ r = self.reporter(config, ["localhost"])
#r.pkgdir = pkdgir
- r.report(ItemStart(item))
+ r.report(report.ItemStart(item))
for outcome in outcomes:
- r.report(ReceivedItemOutcome(None, funcitem, outcome))
+ r.report(report.ReceivedItemOutcome(None, funcitem, outcome))
s = StringIO()
stdoutcopy = sys.stdout
sys.stdout = s
boxfun(pkgdir, config, moditem, funcitem, outcomes)
- sys.stdoud = stdoutcopy
+ sys.stdout = stdoutcopy
+
+ return s.getvalue()
- assert s.getvalue().endswith("test_slave.py[8] FsF."),\
- s.getvalue()
- def test_full_module(self):
+ def _test_full_module(self):
tmpdir = py.test.ensuretemp("repmod")
tmpdir.ensure("__init__.py")
tmpdir.ensure("test_one.py").write(py.code.Source("""
@@ -97,7 +98,7 @@
def boxfun():
config, args = py.test.Config.parse([str(tmpdir)])
rootcol = py.test.collect.Directory(tmpdir)
- r = LocalReporter(config, ["localhost"])
+ r = self.reporter(config, ["localhost"])
list(rootcol.tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x)))
#b = Box(boxfun)
@@ -106,9 +107,71 @@
stdoutcopy = sys.stdout
sys.stdout = s
boxfun()
- sys.stdoud = stdoutcopy
+ sys.stdout = stdoutcopy
- assert s.getvalue() == """
+ return s.getvalue()
+
+ def test_failed_to_load(self):
+ tmpdir = py.test.ensuretemp("failedtoload")
+ tmpdir.ensure("__init__.py")
+ tmpdir.ensure("test_three.py").write(py.code.Source("""
+ sadsadsa
+ """))
+ def boxfun():
+ config, args = py.test.Config.parse([str(tmpdir)])
+ rootcol = py.test.collect.Directory(tmpdir)
+ r = self.reporter(config, ["localhost"])
+ r.report(report.TestStarted(['localhost']))
+ r.report(report.RsyncFinished())
+ list(rootcol.tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x)))
+ r.report(report.TestFinished())
+
+ s = StringIO()
+ stdoutcopy = sys.stdout
+ sys.stdout = s
+ boxfun()
+ sys.stdout = stdoutcopy
+ assert s.getvalue().find("NameError: name 'sadsadsa' is not defined") != -1
+
+class TestLocalReporter(AbstractTestReporter):
+ reporter = LocalReporter
+
+ def test_report_received_item_outcome(self):
+ assert self.report_received_item_outcome() == 'FsF.'
+
+ def test_module(self):
+ assert self._test_module().endswith("test_slave.py[8] FsF."),\
+ self._test_module()
+
+ def test_full_module(self):
+ assert self._test_full_module() == """
repmod/test_one.py[1]
repmod/test_three.py[0] - FAILED TO LOAD MODULE
repmod/test_two.py[0] - skipped (reason)"""
+
+class TestRemoteReporter(AbstractTestReporter):
+ reporter = RemoteReporter
+
+ def test_report_received_item_outcome(self):
+ val = self.report_received_item_outcome()
+ expected = """ localhost: FAILED py test rsession testing test_slave.py funcpass
+ localhost: SKIPPED py test rsession testing test_slave.py funcpass
+ localhost: FAILED py test rsession testing test_slave.py funcpass
+ localhost: PASSED py test rsession testing test_slave.py funcpass
+"""
+ assert val == expected
+
+ def test_module(self):
+ val = self._test_module()
+ print val
+ expected = """ localhost: FAILED py test rsession testing test_slave.py funcpass
+ localhost: SKIPPED py test rsession testing test_slave.py funcpass
+ localhost: FAILED py test rsession testing test_slave.py funcpass
+ localhost: PASSED py test rsession testing test_slave.py funcpass
+"""
+ assert val == expected
+
+ def test_full_module(self):
+ val = self._test_full_module()
+ assert val == 'FAILED TO LOAD MODULE: repmod/test_three.py\n'\
+ '\nSkipped (reason) repmod/test_two.py\n\n'
From guido at codespeak.net Fri Nov 10 11:33:37 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Fri, 10 Nov 2006 11:33:37 +0100 (CET)
Subject: [py-svn] r34451 - in py/dist/py/test/rsession: . testing webdata
Message-ID: <20061110103337.C9C93100BE@code0.codespeak.net>
Author: guido
Date: Fri Nov 10 11:33:34 2006
New Revision: 34451
Added:
py/dist/py/test/rsession/testing/test_webjs.py
Modified:
py/dist/py/test/rsession/webdata/index.html
py/dist/py/test/rsession/webdata/source.js
py/dist/py/test/rsession/webjs.py
Log:
Added first tests for code that is translated to JS (using the mock DOM API
from PyPy), added missing end tag in index.html.
Added: py/dist/py/test/rsession/testing/test_webjs.py
==============================================================================
--- (empty file)
+++ py/dist/py/test/rsession/testing/test_webjs.py Fri Nov 10 11:33:34 2006
@@ -0,0 +1,28 @@
+import py
+try:
+ import pypy
+except ImportError:
+ py.test.skip('missing PyPy')
+from pypy.translator.js.modules import dom
+from py.__.test.rsession import webjs
+
+here = py.magic.autopath().dirpath()
+
+def setup_module(mod):
+ # load HTML into window object
+ html = here.join('../webdata/index.html').read()
+ dom.window = dom.Window(html)
+
+def test_html_loaded():
+ body = dom.window.document.getElementsByTagName('body')[0]
+ assert len(body.childNodes) > 0
+ assert str(body.childNodes[1].nodeName) == 'A'
+
+def test_set_msgbox():
+ msgbox = dom.window.document.getElementById('messagebox')
+ assert len(msgbox.childNodes) == 0
+ webjs.set_msgbox('foo', 'bar')
+ assert len(msgbox.childNodes) == 1
+ assert msgbox.childNodes[0].nodeName == 'PRE'
+ assert msgbox.childNodes[0].childNodes[0].nodeValue == 'foo\nbar'
+
Modified: py/dist/py/test/rsession/webdata/index.html
==============================================================================
--- py/dist/py/test/rsession/webdata/index.html (original)
+++ py/dist/py/test/rsession/webdata/index.html Fri Nov 10 11:33:34 2006
@@ -2,6 +2,7 @@
Py.test
Modified: py/dist/py/test/rsession/webdata/source.js
==============================================================================
Binary files. No diff available.
Modified: py/dist/py/test/rsession/webjs.py
==============================================================================
--- py/dist/py/test/rsession/webjs.py (original)
+++ py/dist/py/test/rsession/webjs.py Fri Nov 10 11:33:34 2006
@@ -5,7 +5,7 @@
import py
from py.__.test.rsession.web import exported_methods
try:
- from pypy.translator.js.modules import _dom as dom
+ from pypy.translator.js.modules import dom
from pypy.translator.js.helper import __show_traceback
from pypy.translator.transformer.debug import traceback_handler
except ImportError:
From fijal at codespeak.net Sat Nov 11 14:03:57 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 11 Nov 2006 14:03:57 +0100 (CET)
Subject: [py-svn] r34484 - py/dist/py/test/rsession
Message-ID: <20061111130357.1970410105@code0.codespeak.net>
Author: fijal
Date: Sat Nov 11 14:03:56 2006
New Revision: 34484
Modified:
py/dist/py/test/rsession/hostmanage.py
py/dist/py/test/rsession/web.py
Log:
Ooops, forgotten checkin.
Modified: py/dist/py/test/rsession/hostmanage.py
==============================================================================
--- py/dist/py/test/rsession/hostmanage.py (original)
+++ py/dist/py/test/rsession/hostmanage.py Sat Nov 11 14:03:56 2006
@@ -27,7 +27,7 @@
else:
return base in self.rsync_roots
-def prepare_gateway(sshosts, relpath, rsync_roots, optimise_localhost, remote_python):
+def prepare_gateway(sshosts, relpath, rsync_roots, optimise_localhost, remote_python, pkgdir):
hosts = []
for host in sshosts:
if host != 'localhost' or not optimise_localhost:
@@ -70,7 +70,7 @@
nodes = []
exc_info = [None]
hosts = prepare_gateway(sshhosts, relpath, rsync_roots, optimise_localhost,
- remote_python)
+ remote_python, pkgdir)
# rsyncing
if optimise_localhost:
Modified: py/dist/py/test/rsession/web.py
==============================================================================
--- py/dist/py/test/rsession/web.py (original)
+++ py/dist/py/test/rsession/web.py Sat Nov 11 14:03:56 2006
@@ -33,7 +33,7 @@
from pypy.translator.js.main import rpython2javascript, Options
from pypy.translator.js import commproxy
- Options.debug_transform = True
+ Options.debug_transform = False
commproxy.USE_MOCHIKIT = False
IMPORTED_PYPY = True
except ImportError:
From fijal at codespeak.net Sat Nov 11 14:30:36 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 11 Nov 2006 14:30:36 +0100 (CET)
Subject: [py-svn] r34487 - py/dist/py/test/rsession
Message-ID: <20061111133036.243CE1010D@code0.codespeak.net>
Author: fijal
Date: Sat Nov 11 14:30:34 2006
New Revision: 34487
Modified:
py/dist/py/test/rsession/hostmanage.py
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/slave.py
Log:
Make easier teardown when using -x.
Modified: py/dist/py/test/rsession/hostmanage.py
==============================================================================
--- py/dist/py/test/rsession/hostmanage.py (original)
+++ py/dist/py/test/rsession/hostmanage.py Sat Nov 11 14:30:34 2006
@@ -97,11 +97,12 @@
return nodes
-def teardown_hosts(reporter, channels, nodes, waiter=lambda : time.sleep(.1)):
+def teardown_hosts(reporter, channels, nodes, waiter=lambda : time.sleep(.1),
+ exitfirst=False):
for channel in channels:
channel.send(None)
- clean = False
+ clean = exitfirst
while not clean:
clean = True
for node in nodes:
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Sat Nov 11 14:30:34 2006
@@ -139,6 +139,7 @@
remotepython = None
remote_options['nomagic'] = self.config.option.nomagic
+ remote_options['exitfirst'] = self.config.option.exitfirst
nodes = init_hosts(reporter, sshhosts, directories, pkgdir,
rsync_roots, remotepython, remote_options=remote_options.d,
optimise_localhost=self.optimise_localhost)
@@ -155,7 +156,8 @@
#assert 0, "\n".join([",".join(x.listnames()) for x in
# list(itemgenerator)])
dispatch_loop(nodes, itemgenerator, checkfun)
- teardown_hosts(reporter, [node.channel for node in nodes], nodes)
+ teardown_hosts(reporter, [node.channel for node in nodes], nodes,
+ exitfirst=self.config.option.exitfirst)
reporter(report.Nodes(nodes))
reporter(report.TestFinished())
if startserverflag:
Modified: py/dist/py/test/rsession/slave.py
==============================================================================
--- py/dist/py/test/rsession/slave.py (original)
+++ py/dist/py/test/rsession/slave.py Sat Nov 11 14:30:34 2006
@@ -54,8 +54,14 @@
excinfo = py.code.ExceptionInfo()
send(Outcome(excinfo=excinfo, is_critical=True).make_repr())
else:
+ if not res[0] and py.test.remote.exitfirst:
+ # we're finished, but need to eat what we can
+ send(res)
+ break
send(res)
-
+
+ while nextitem is not None:
+ nextitem = receive()
def setup():
default_options = {'nomagic':False} # XXX should come from somewhere else
From fijal at codespeak.net Sat Nov 11 20:42:02 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 11 Nov 2006 20:42:02 +0100 (CET)
Subject: [py-svn] r34506 - in py/dist/py/test/rsession: . testing
Message-ID: <20061111194202.2F6D91011E@code0.codespeak.net>
Author: fijal
Date: Sat Nov 11 20:42:00 2006
New Revision: 34506
Modified:
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/testing/test_rsession.py
Log:
Test for -x on RSession.
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Sat Nov 11 20:42:00 2006
@@ -138,10 +138,11 @@
except:
remotepython = None
- remote_options['nomagic'] = self.config.option.nomagic
- remote_options['exitfirst'] = self.config.option.exitfirst
+ rem_options = RemoteOptions({})
+ rem_options['nomagic'] = self.config.option.nomagic
+ rem_options['exitfirst'] = self.config.option.exitfirst
nodes = init_hosts(reporter, sshhosts, directories, pkgdir,
- rsync_roots, remotepython, remote_options=remote_options.d,
+ rsync_roots, remotepython, remote_options=rem_options.d,
optimise_localhost=self.optimise_localhost)
reporter(report.RsyncFinished())
Modified: py/dist/py/test/rsession/testing/test_rsession.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rsession.py (original)
+++ py/dist/py/test/rsession/testing/test_rsession.py Sat Nov 11 20:42:00 2006
@@ -107,7 +107,34 @@
## channel.send(None)
## res = channel.receive()
## assert res == "ok"
-
+
+ def test_example_distribution_minus_x(self):
+ # XXX find a better way for the below
+ tmpdir = py.path.local(py.__file__).dirpath().dirpath()
+ tmpdir.ensure("sub", "conftest.py").write(py.code.Source("""
+ disthosts = [%r]
+ distrsync_roots = ["sub", "py"]
+ """ % 'localhost'))
+ tmpdir.ensure("sub", "__init__.py")
+ tmpdir.ensure("sub", "test_one.py").write(py.code.Source("""
+ def test_1():
+ pass
+ def test_2():
+ assert 0
+ def test_3():
+ raise ValueError(23)
+ def test_4(someargs):
+ pass
+ """))
+ args = [str(tmpdir.join("sub")), "-x"]
+ config, args = py.test.Config.parse(args)
+ rsession = RSession(config)
+ allevents = []
+ rsession.main(args, reporter=allevents.append)
+ testevents = [x for x in allevents
+ if isinstance(x, report.ReceivedItemOutcome)]
+ assert len(testevents) == 2
+
def test_example_distribution(self):
# XXX find a better way for the below
tmpdir = py.path.local(py.__file__).dirpath().dirpath()
@@ -159,7 +186,7 @@
teardown_events = []
nodes = init_hosts(setup_events.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"], optimise_localhost=False)
+ rsync_roots=["py"], optimise_localhost=False, remote_options={'exitfirst':False})
teardown_hosts(teardown_events.append,
[node.channel for node in nodes], nodes)
@@ -183,7 +210,7 @@
allevents = []
nodes = init_hosts(allevents.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"], optimise_localhost=False)
+ rsync_roots=["py"], optimise_localhost=False, remote_options={'exitfirst':False})
from py.__.test.rsession.testing.test_executor \
import ItemTestPassing, ItemTestFailing, ItemTestSkipping
@@ -222,7 +249,7 @@
allevents = []
hosts = ['localhost']
nodes = init_hosts(allevents.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"], remote_options={'custom':'custom'},
+ rsync_roots=["py"], remote_options={'custom':'custom', 'exitfirst':False},
optimise_localhost=False)
rootcol = py.test.collect.Directory(pkgdir.dirpath())
From fijal at codespeak.net Sat Nov 11 21:08:05 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sat, 11 Nov 2006 21:08:05 +0100 (CET)
Subject: [py-svn] r34510 - py/dist/py/test/rsession
Message-ID: <20061111200805.B7EB010130@code0.codespeak.net>
Author: fijal
Date: Sat Nov 11 21:08:04 2006
New Revision: 34510
Modified:
py/dist/py/test/rsession/rsession.py
Log:
Ooops, forgotten to commit that one.
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Sat Nov 11 21:08:04 2006
@@ -29,7 +29,8 @@
def __setitem__(self, item, val):
self.d[item] = val
-remote_options = RemoteOptions({'we_are_remote':False})
+# XXX: Must be initialised somehow
+remote_options = RemoteOptions({'we_are_remote':False, 'exitfirst':False})
class AbstractSession(object):
"""
From fijal at codespeak.net Sun Nov 12 00:25:20 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sun, 12 Nov 2006 00:25:20 +0100 (CET)
Subject: [py-svn] r34517 - py/dist/py/test
Message-ID: <20061111232520.3009D10135@code0.codespeak.net>
Author: fijal
Date: Sun Nov 12 00:25:18 2006
New Revision: 34517
Modified:
py/dist/py/test/config.py
Log:
Deholgerizing.
Modified: py/dist/py/test/config.py
==============================================================================
--- py/dist/py/test/config.py (original)
+++ py/dist/py/test/config.py Sun Nov 12 00:25:18 2006
@@ -162,7 +162,7 @@
# access to the resulting config values?
config = Config._config
- # trigger loading conftest files which might add options!
+ # trigger loading conftest files which might add options!
for configpath in configpaths:
config.loadconfig(configpath)
config.loadconfig(defaultconfig).adddefaultoptions()
From fijal at codespeak.net Sun Nov 12 00:27:06 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sun, 12 Nov 2006 00:27:06 +0100 (CET)
Subject: [py-svn] r34518 - in py/dist/py/test/rsession: . testing
Message-ID: <20061111232706.5696610136@code0.codespeak.net>
Author: fijal
Date: Sun Nov 12 00:27:04 2006
New Revision: 34518
Modified:
py/dist/py/test/rsession/hostmanage.py
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/testing/test_rsession.py
Log:
Major refactoring of rsession rsync attempt. Now you can specify multiple times the same host and control how many times you would like to rsync. And test for the above ;-)
Modified: py/dist/py/test/rsession/hostmanage.py
==============================================================================
--- py/dist/py/test/rsession/hostmanage.py (original)
+++ py/dist/py/test/rsession/hostmanage.py Sun Nov 12 00:27:04 2006
@@ -29,13 +29,13 @@
def prepare_gateway(sshosts, relpath, rsync_roots, optimise_localhost, remote_python, pkgdir):
hosts = []
- for host in sshosts:
+ for num, host in enumerate(sshosts):
if host != 'localhost' or not optimise_localhost:
if isinstance(relpath, str):
assert not os.path.isabs(relpath), relpath
remoterootpath = relpath
else:
- remoterootpath = relpath[host]
+ remoterootpath = relpath[(num, host)]
# XXX: because of NFS we do create different directories
# otherwise, .pyc files overlap
remoterootpath += "-" + host
@@ -51,46 +51,53 @@
else:
gw = py.execnet.SshGateway(host, remotepython=remote_python)
- hosts.append((host, gw, remoterootpath))
+ hosts.append((num, host, gw, remoterootpath))
else:
if remote_python is None:
gw = py.execnet.PopenGateway()
else:
gw = py.execnet.PopenGateway(remotepython=remote_python)
gw.sshaddress = 'localhost'
- hosts.append((host, gw, str(pkgdir.dirpath())))
+ hosts.append((num, host, gw, str(pkgdir.dirpath())))
return hosts
+# XXX: Options has grown a bit too much, but most of them is just for tests
def init_hosts(reporter, sshhosts, relpath, pkgdir, rsync_roots=None, \
- remote_python=None, remote_options={}, optimise_localhost=True):
+ remote_python=None, remote_options={}, optimise_localhost=True,\
+ do_sync=True):
assert pkgdir.join("__init__.py").check(), (
"%s probably wrong" %(pkgdir,))
assert relpath, relpath
- nodes = []
exc_info = [None]
hosts = prepare_gateway(sshhosts, relpath, rsync_roots, optimise_localhost,
remote_python, pkgdir)
# rsyncing
- if optimise_localhost:
- rsynced = {'localhost':True}
- else:
- rsynced = {}
-
- rsync = HostRSync(rsync_roots)
- for host, gw, remoterootpath in hosts:
- if host in rsynced:
+ rsynced = {}
+
+ if do_sync:
+ rsync = HostRSync(rsync_roots)
+ for num, host, gw, remoterootpath in hosts:
+ if (host, remoterootpath) in rsynced or (host == 'localhost' \
+ and optimise_localhost):
continue
- rsynced[host] = True
+ rsynced[(host, remoterootpath)] = True
def done(host=host):
reporter(report.HostReady(host))
reporter(report.HostRSyncing(host, remoterootpath))
- rsync.add_target(gw, remoterootpath, done)
+ if do_sync:
+ rsync.add_target(gw, remoterootpath, done)
+ if not do_sync:
+ return # for testing only
rsync.send(pkgdir.dirpath())
# hosts ready
- for host, gw, remoterootpath in hosts:
+ return setup_nodes(hosts, pkgdir, remote_options, reporter)
+
+def setup_nodes(hosts, pkgdir, remote_options, reporter):
+ nodes = []
+ for num, host, gw, remoterootpath in hosts:
ch = setup_slave(gw, os.path.join(remoterootpath, pkgdir.basename),
remote_options)
nodes.append(MasterNode(ch, reporter))
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Sun Nov 12 00:27:04 2006
@@ -106,6 +106,19 @@
reporter(report.FailedTryiter(excinfo, item))
reporterror = staticmethod(reporterror)
+def parse_directories(sshhosts):
+ # dictionary containing directories for hosts
+ # XXX: should be class with some info like key, etc. in future
+ directories = {}
+ for num, host in enumerate(sshhosts):
+ m = re.match("^(.*?):(.*)$", host)
+ if m:
+ directories[(num, m.group(1))] = m.group(2)
+ sshhosts[num] = m.group(1)
+ else:
+ directories[(num, host)] = "pytestcache"
+ return directories
+
class RSession(AbstractSession):
""" Remote version of session
"""
@@ -114,16 +127,7 @@
if not args:
args = [py.path.local()]
sshhosts = self.config.getinitialvalue("disthosts")
- # dictionary containing directories for hosts
- # XXX: should be class with some info like key, etc. in future
- directories = {}
- for num, host in enumerate(sshhosts):
- m = re.match("^(.*?):(.*)$", host)
- if m:
- directories[m.group(1)] = m.group(2)
- sshhosts[num] = m.group(1)
- else:
- directories[host] = "pytestcache"
+ directories = parse_directories(sshhosts)
try:
rsync_roots = self.config.getinitialvalue("distrsync_roots")
except:
@@ -155,8 +159,6 @@
yield y
itemgenerator = itemgen()
- #assert 0, "\n".join([",".join(x.listnames()) for x in
- # list(itemgenerator)])
dispatch_loop(nodes, itemgenerator, checkfun)
teardown_hosts(reporter, [node.channel for node in nodes], nodes,
exitfirst=self.config.option.exitfirst)
Modified: py/dist/py/test/rsession/testing/test_rsession.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rsession.py (original)
+++ py/dist/py/test/rsession/testing/test_rsession.py Sun Nov 12 00:27:04 2006
@@ -4,7 +4,7 @@
import py
from py.__.test.rsession import report
-from py.__.test.rsession.rsession import RSession
+from py.__.test.rsession.rsession import RSession, parse_directories
from py.__.test.rsession.hostmanage import init_hosts, teardown_hosts
from py.__.test.rsession.testing.test_slave import funcfail_spec,\
funcpass_spec, funcskip_spec, funcprint_spec, funcprintfail_spec, \
@@ -270,3 +270,39 @@
assert len(passed) == 2 * len(nodes)
assert len(skipped) == 0
assert len(events) == len(passed)
+
+class TestDirectories(object):
+ def test_simple_parse(self):
+ sshhosts = ['h1', 'h2', 'h3']
+ dirs = parse_directories(sshhosts)
+ assert len(set(dirs.values())) == 1
+ assert sorted(dirs.keys()) == [(0, 'h1'), (1, 'h2'), (2, 'h3')]
+
+ def test_sophisticated_parse(self):
+ sshhosts = ['a at h1:/tmp', 'h2:tmp', 'h3']
+ dirs = parse_directories(sshhosts)
+ assert sorted(dirs.values()) == ['/tmp', 'pytestcache', 'tmp']
+
+ def test_parse_multiple_hosts(self):
+ hosts = ['h1', 'h1', 'h1:/tmp']
+ dirs = parse_directories(hosts)
+ assert dirs == {(0, 'h1'): 'pytestcache', (1, 'h1'): 'pytestcache',
+ (2, 'h1'):'/tmp'}
+
+class TestInithosts(object):
+ def test_inithosts(self):
+ testevents = []
+ hosts = ['h1:/tmp', 'h1:/tmp', 'h1:/other', 'h2', 'h2:home']
+ dirs = parse_directories(hosts)
+ init_hosts(testevents.append, hosts, dirs, pkgdir, do_sync=False)
+ events = [i for i in testevents if isinstance(i, report.HostRSyncing)]
+ assert len(events) == 4
+ assert events[0].hostname == 'h1'
+ assert events[0].remoterootpath == '/tmp-h1'
+ assert events[1].hostname == 'h1'
+ assert events[1].remoterootpath == '/other-h1'
+ assert events[2].hostname == 'h2'
+ assert events[2].remoterootpath == 'pytestcache-h2'
+ assert events[3].hostname == 'h2'
+ assert events[3].remoterootpath == 'home-h2'
+
From fijal at codespeak.net Sun Nov 12 00:29:29 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sun, 12 Nov 2006 00:29:29 +0100 (CET)
Subject: [py-svn] r34519 - py/dist/py/test/rsession
Message-ID: <20061111232929.C360D1013C@code0.codespeak.net>
Author: fijal
Date: Sun Nov 12 00:29:28 2006
New Revision: 34519
Modified:
py/dist/py/test/rsession/rsession.py
Log:
Changed default LSession runner.
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Sun Nov 12 00:29:28 2006
@@ -201,10 +201,12 @@
self.docstorage = DocStorage().from_pkg(module)
self.tracer = Tracer(self.docstorage)
runner = apigen_runner
- elif runner is None and (self.config.option.usepdb or self.config.option.nocapture):
- runner = plain_runner
+ #elif runner is None and (self.config.option.usepdb or self.config.option.nocapture):
+ # runner = plain_runner
+ #elif runner is None:
+ # runner = box_runner
elif runner is None:
- runner = box_runner
+ runner = plain_runner
keyword = self.config.option.keyword
From fijal at codespeak.net Sun Nov 12 21:24:16 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Sun, 12 Nov 2006 21:24:16 +0100 (CET)
Subject: [py-svn] r34534 - py/dist/py/test
Message-ID: <20061112202416.16D661015D@code0.codespeak.net>
Author: fijal
Date: Sun Nov 12 21:24:15 2006
New Revision: 34534
Modified:
py/dist/py/test/collect.py
Log:
Add a bit of heuristic for collection order (it's better than it was before).
Modified: py/dist/py/test/collect.py
==============================================================================
--- py/dist/py/test/collect.py (original)
+++ py/dist/py/test/collect.py Sun Nov 12 21:24:15 2006
@@ -120,8 +120,8 @@
return property(fget, fset, None, "underlying object")
obj = obj()
- def _getobj(self):
- return getattr(self.parent.obj, self.name)
+ def _getobj(self):
+ return getattr(self.parent.obj, self.name)
def multijoin(self, namelist):
""" return a list of colitems for the given namelist. """
@@ -421,8 +421,16 @@
teardown_class = getattr(teardown_class, 'im_func', teardown_class)
teardown_class(self.obj)
- def getsortvalue(self):
- for x in self.tryiter((py.test.collect.Generator, py.test.Item)):
+ def getsortvalue(self):
+ try:
+ for key, val in self.obj.__dict__.iteritems():
+ import types
+ if type(val) is (types.FunctionType, types.GeneratorType):
+ return val.func_code.co_firstlineno
+ except AttributeError:
+ pass
+ # fall back...
+ for x in self.tryiter((py.test.collect.Generator, py.test.Item)):
return x.getsortvalue()
class Instance(PyCollectorMixin, Collector):
From fijal at codespeak.net Mon Nov 13 12:21:50 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 12:21:50 +0100 (CET)
Subject: [py-svn] r34550 - py/dist/py/test/rsession/testing
Message-ID: <20061113112150.ECB1810182@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 12:21:48 2006
New Revision: 34550
Modified:
py/dist/py/test/rsession/testing/test_web.py
Log:
Skip the test till guido fix it.
Modified: py/dist/py/test/rsession/testing/test_web.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_web.py (original)
+++ py/dist/py/test/rsession/testing/test_web.py Mon Nov 13 12:21:48 2006
@@ -15,6 +15,7 @@
py.test.skip("No PyPy detected")
def test_js_generate():
+ py.test.skip("XXX")
from py.__.test.rsession import webjs
from py.__.test.rsession.web import FUNCTION_LIST
From fijal at codespeak.net Mon Nov 13 12:22:16 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 12:22:16 +0100 (CET)
Subject: [py-svn] r34551 - in py/dist/py/test/rsession: . testing
Message-ID: <20061113112216.4FF4310184@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 12:22:13 2006
New Revision: 34551
Added:
py/dist/py/test/rsession/testing/test_config.py (contents, props changed)
Modified:
py/dist/py/test/rsession/local.py
py/dist/py/test/rsession/master.py
py/dist/py/test/rsession/rsession.py
Log:
Refactored session options (starting point) for having central point for those.
Modified: py/dist/py/test/rsession/local.py
==============================================================================
--- py/dist/py/test/rsession/local.py (original)
+++ py/dist/py/test/rsession/local.py Mon Nov 13 12:22:13 2006
@@ -33,6 +33,11 @@
outcome.stdout, outcome.stderr = finishcapture(session)
return outcome
+RunnerPolicy = {
+ 'plain_runner':plain_runner,
+ 'box_runner':box_runner
+}
+
def benchmark_runner(item, session, reporter):
raise NotImplementedError()
Modified: py/dist/py/test/rsession/master.py
==============================================================================
--- py/dist/py/test/rsession/master.py (original)
+++ py/dist/py/test/rsession/master.py Mon Nov 13 12:22:13 2006
@@ -5,8 +5,6 @@
from py.__.test.rsession.outcome import ReprOutcome
from py.__.test.rsession import report
-MAX_TASKS_PER_NODE = 15
-
class MasterNode(object):
def __init__(self, channel, reporter):
self.channel = channel
@@ -29,12 +27,14 @@
self.reporter(report.SendItem(self.channel, item))
def dispatch_loop(masternodes, itemgenerator, shouldstop,
- waiter = lambda: py.std.time.sleep(0.1),
- maxtasks_per_node = MAX_TASKS_PER_NODE):
+ waiter = lambda: py.std.time.sleep(0.1)):
+ from py.__.test.rsession.rsession import session_options
+
+ max_tasks_per_node = session_options.max_tasks_per_node
while 1:
try:
for node in masternodes:
- if len(node.pending) < maxtasks_per_node:
+ if len(node.pending) < max_tasks_per_node:
item = itemgenerator.next()
if shouldstop():
return
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Mon Nov 13 12:22:13 2006
@@ -14,7 +14,7 @@
from py.__.test.rsession.hostmanage import init_hosts, teardown_hosts
from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\
- box_runner
+ box_runner, RunnerPolicy
from py.__.test.rsession.reporter import LocalReporter, RemoteReporter
class RemoteOptions(object):
@@ -31,6 +31,36 @@
# XXX: Must be initialised somehow
remote_options = RemoteOptions({'we_are_remote':False, 'exitfirst':False})
+
+class SessionOptions:
+ defaults = {
+ 'max_tasks_per_node' : 15,
+ 'runner_policy' : 'plain_runner'
+ }
+
+ config = None
+
+ def getvalue(self, opt):
+ try:
+ return getattr(self.config.getinitialvalue('SessionOptions'), opt)
+ except (ValueError, AttributeError):
+ try:
+ return self.defaults[opt]
+ except KeyError:
+ raise AttributeError("Option %s undeclared" % opt)
+
+ def bind_config(self, config):
+ self.config = config
+
+ def __repr__(self):
+ return "" % self.config
+
+ def __getattr__(self, attr):
+ if self.config is None:
+ raise NotImplementedError("Need to set up config first")
+ return self.getvalue(attr)
+
+session_options = SessionOptions()
class AbstractSession(object):
"""
@@ -158,7 +188,8 @@
for y in x.tryiter(reporterror = lambda x: self.reporterror(reporter, x), keyword = keyword):
yield y
- itemgenerator = itemgen()
+ itemgenerator = itemgen()
+ session_options.bind_config(self.config)
dispatch_loop(nodes, itemgenerator, checkfun)
teardown_hosts(reporter, [node.channel for node in nodes], nodes,
exitfirst=self.config.option.exitfirst)
@@ -191,6 +222,7 @@
pkgdir = self.getpkgdir(args[0])
colitems = self.make_colitems(args, baseon=pkgdir.dirpath())
reporter(report.RsyncFinished())
+ session_options.bind_config(self.config)
if runner is None and self.config.option.apigen:
from py.__.apigen.tracer.docstorage import DocStorage
@@ -206,7 +238,7 @@
#elif runner is None:
# runner = box_runner
elif runner is None:
- runner = plain_runner
+ runner = RunnerPolicy[session_options.runner_policy]
keyword = self.config.option.keyword
Added: py/dist/py/test/rsession/testing/test_config.py
==============================================================================
--- (empty file)
+++ py/dist/py/test/rsession/testing/test_config.py Mon Nov 13 12:22:13 2006
@@ -0,0 +1,21 @@
+
+""" test session config options
+"""
+
+import py
+from py.__.test.rsession.rsession import session_options, SessionOptions
+
+def test_session_opts():
+ tmpdir = py.test.ensuretemp("sessionopts")
+ tmpdir.ensure("conftest.py").write("""class SessionOptions:
+ max_tasks_per_node = 5
+ """)
+ tmp2 = py.test.ensuretemp("xxx")
+ args = [str(tmpdir)]
+ config, args = py.test.Config.parse(args)
+ session_options.bind_config(config)
+ assert session_options.max_tasks_per_node == 5
+ config, args = py.test.Config.parse([str(tmp2)])
+ session_options.bind_config(config)
+ assert session_options.max_tasks_per_node == \
+ SessionOptions.defaults['max_tasks_per_node']
From fijal at codespeak.net Mon Nov 13 13:20:16 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 13:20:16 +0100 (CET)
Subject: [py-svn] r34555 - in py/dist/py/test/rsession: . testing
Message-ID: <20061113122016.3383310190@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 13:20:13 2006
New Revision: 34555
Modified:
py/dist/py/test/rsession/box.py
py/dist/py/test/rsession/master.py
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/slave.py
py/dist/py/test/rsession/testing/test_boxing.py
py/dist/py/test/rsession/testing/test_master.py
py/dist/py/test/rsession/testing/test_rsession.py
py/dist/py/test/rsession/testing/test_slave.py
Log:
A lot of refactoring of SessionOptions. Now nice level should work.
Modified: py/dist/py/test/rsession/box.py
==============================================================================
--- py/dist/py/test/rsession/box.py (original)
+++ py/dist/py/test/rsession/box.py Mon Nov 13 13:20:13 2006
@@ -8,7 +8,7 @@
import sys
import marshal
-NICE_LEVEL = 0 # XXX make it a conftest option
+#NICE_LEVEL = 0 # XXX make it a conftest option
PYTESTSTDOUT = "pyteststdout"
PYTESTSTDERR = "pyteststderr"
@@ -55,12 +55,14 @@
self.PYTESTRETVAL = tempdir.join('retval')
self.PYTESTSTDOUT = tempdir.join('stdout')
self.PYTESTSTDERR = tempdir.join('stderr')
+
+ nice_level = py.test.remote.nice_level
pid = os.fork()
if pid:
self.parent()
else:
try:
- outcome = self.children()
+ outcome = self.children(nice_level)
except:
excinfo = py.code.ExceptionInfo()
print "Internal box error"
@@ -73,7 +75,7 @@
os._exit(0)
return pid
- def children(self):
+ def children(self, nice_level):
# right now we need to call a function, but first we need to
# map all IO that might happen
# make sure sys.stdout points to file descriptor one
@@ -88,8 +90,9 @@
os.dup2(fdstderr, 2)
retvalf = self.PYTESTRETVAL.open("w")
try:
- if NICE_LEVEL:
- os.nice(NICE_LEVEL)
+ from py.__.test.rsession.rsession import remote_options
+ if nice_level:
+ os.nice(nice_level)
retval = self.fun(*self.args, **self.kwargs)
retvalf.write(marshal.dumps(retval))
finally:
Modified: py/dist/py/test/rsession/master.py
==============================================================================
--- py/dist/py/test/rsession/master.py (original)
+++ py/dist/py/test/rsession/master.py Mon Nov 13 13:20:13 2006
@@ -43,7 +43,7 @@
break
waiter()
-def setup_slave(gateway, pkgpath, options={}):
+def setup_slave(gateway, pkgpath, options):
from py.__.test.rsession import slave
import os
ch = gateway.remote_exec(str(py.code.Source(slave.setup, "setup()")))
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Mon Nov 13 13:20:13 2006
@@ -30,12 +30,13 @@
self.d[item] = val
# XXX: Must be initialised somehow
-remote_options = RemoteOptions({'we_are_remote':False, 'exitfirst':False})
-
+remote_options = RemoteOptions({'we_are_remote':False})
+
class SessionOptions:
defaults = {
'max_tasks_per_node' : 15,
- 'runner_policy' : 'plain_runner'
+ 'runner_policy' : 'plain_runner',
+ 'nice_level' : 0,
}
config = None
@@ -51,6 +52,20 @@
def bind_config(self, config):
self.config = config
+ # copy to remote all options
+ for item, val in config.option.__dict__.items():
+ remote_options[item] = val
+ # as well as some options from us
+ try:
+ ses_opt = self.config.getinitialvalue('SessionOptions').__dict__
+ except ValueError:
+ ses_opt = self.defaults
+ for key in self.defaults:
+ try:
+ val = getattr(ses_opt, key)
+ except AttributeError:
+ val = self.defaults[key]
+ remote_options[key] = val
def __repr__(self):
return "" % self.config
@@ -173,11 +188,9 @@
except:
remotepython = None
- rem_options = RemoteOptions({})
- rem_options['nomagic'] = self.config.option.nomagic
- rem_options['exitfirst'] = self.config.option.exitfirst
+ session_options.bind_config(self.config)
nodes = init_hosts(reporter, sshhosts, directories, pkgdir,
- rsync_roots, remotepython, remote_options=rem_options.d,
+ rsync_roots, remotepython, remote_options=remote_options.d,
optimise_localhost=self.optimise_localhost)
reporter(report.RsyncFinished())
@@ -189,7 +202,6 @@
yield y
itemgenerator = itemgen()
- session_options.bind_config(self.config)
dispatch_loop(nodes, itemgenerator, checkfun)
teardown_hosts(reporter, [node.channel for node in nodes], nodes,
exitfirst=self.config.option.exitfirst)
Modified: py/dist/py/test/rsession/slave.py
==============================================================================
--- py/dist/py/test/rsession/slave.py (original)
+++ py/dist/py/test/rsession/slave.py Mon Nov 13 13:20:13 2006
@@ -64,9 +64,6 @@
nextitem = receive()
def setup():
- default_options = {'nomagic':False} # XXX should come from somewhere else
- # but I don't want to mess with conftest at this point
-
import os, sys
pkgdir = channel.receive() # path is ready
options = channel.receive() # options stuff, should be dictionary
@@ -76,9 +73,6 @@
sys.path.insert(0, basedir)
import py
options['we_are_remote'] = True
- for opt, val in default_options.items():
- if opt not in options:
- options[opt] = val
from py.__.test.rsession.rsession import RemoteOptions
py.test.remote = RemoteOptions(options)
# XXX the following assumes that py lib is there, a bit
Modified: py/dist/py/test/rsession/testing/test_boxing.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_boxing.py (original)
+++ py/dist/py/test/rsession/testing/test_boxing.py Mon Nov 13 13:20:13 2006
@@ -11,6 +11,10 @@
from py.__.test.rsession.testing import example2
from py.__.test.rsession.conftest import option
+def setup_module(mod):
+ from py.__.test.rsession.rsession import remote_options
+ remote_options['nice_level'] = 0
+
def test_basic_boxing():
# XXX: because we do not have option transfer
## if not hasattr(option, 'nocapture') or not option.nocapture:
Modified: py/dist/py/test/rsession/testing/test_master.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_master.py (original)
+++ py/dist/py/test/rsession/testing/test_master.py Mon Nov 13 13:20:13 2006
@@ -13,8 +13,13 @@
from py.__.test.rsession.outcome import ReprOutcome, Outcome
from py.__.test.rsession.testing.test_slave import funcpass_spec, funcfail_spec
from py.__.test.rsession import report
+from py.__.test.rsession.rsession import session_options, remote_options
def setup_module(mod):
+ # bind an empty config
+ config, args = py.test.Config.parse([])
+ session_options.bind_config(config)
+ #assert not remote_options.exitfirst
mod.pkgdir = py.path.local(py.__file__).dirpath()
class DummyChannel(object):
@@ -70,7 +75,7 @@
def test_slave_setup():
gw = py.execnet.PopenGateway()
- channel = setup_slave(gw, pkgdir)
+ channel = setup_slave(gw, pkgdir, remote_options.d)
channel.send(funcpass_spec)
output = ReprOutcome(channel.receive())
assert output.passed
@@ -90,7 +95,7 @@
def open_gw():
gw = py.execnet.PopenGateway()
- channel = setup_slave(gw, pkgdir)
+ channel = setup_slave(gw, pkgdir, remote_options.d)
mn = MasterNode(channel, simple_report)
return mn
Modified: py/dist/py/test/rsession/testing/test_rsession.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rsession.py (original)
+++ py/dist/py/test/rsession/testing/test_rsession.py Mon Nov 13 13:20:13 2006
@@ -4,7 +4,8 @@
import py
from py.__.test.rsession import report
-from py.__.test.rsession.rsession import RSession, parse_directories
+from py.__.test.rsession.rsession import RSession, parse_directories,\
+ session_options, remote_options
from py.__.test.rsession.hostmanage import init_hosts, teardown_hosts
from py.__.test.rsession.testing.test_slave import funcfail_spec,\
funcpass_spec, funcskip_spec, funcprint_spec, funcprintfail_spec, \
@@ -185,8 +186,10 @@
setup_events = []
teardown_events = []
+ config, args = py.test.Config.parse([])
+ session_options.bind_config(config)
nodes = init_hosts(setup_events.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"], optimise_localhost=False, remote_options={'exitfirst':False})
+ rsync_roots=["py"], optimise_localhost=False, remote_options=remote_options.d)
teardown_hosts(teardown_events.append,
[node.channel for node in nodes], nodes)
@@ -209,8 +212,10 @@
hosts = ['localhost']
allevents = []
+ config, args = py.test.Config.parse([])
+ session_options.bind_config(config)
nodes = init_hosts(allevents.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"], optimise_localhost=False, remote_options={'exitfirst':False})
+ rsync_roots=["py"], optimise_localhost=False, remote_options=remote_options.d)
from py.__.test.rsession.testing.test_executor \
import ItemTestPassing, ItemTestFailing, ItemTestSkipping
@@ -248,8 +253,12 @@
"""
allevents = []
hosts = ['localhost']
+ config, args = py.test.Config.parse([])
+ session_options.bind_config(config)
+ d = remote_options.d.copy()
+ d['custom'] = 'custom'
nodes = init_hosts(allevents.append, hosts, 'pytesttest', pkgdir,
- rsync_roots=["py"], remote_options={'custom':'custom', 'exitfirst':False},
+ rsync_roots=["py"], remote_options=d,
optimise_localhost=False)
rootcol = py.test.collect.Directory(pkgdir.dirpath())
Modified: py/dist/py/test/rsession/testing/test_slave.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_slave.py (original)
+++ py/dist/py/test/rsession/testing/test_slave.py Mon Nov 13 13:20:13 2006
@@ -11,7 +11,10 @@
py.test.skip("rsession is unsupported on Windows.")
def setup_module(module):
+ from py.__.test.rsession.rsession import session_options
module.rootdir = py.path.local(py.__file__).dirpath().dirpath()
+ config, args = py.test.Config.parse([])
+ session_options.bind_config(config)
# ----------------------------------------------------------------------
# inlined testing functions used below
@@ -109,8 +112,7 @@
slave_main(q.pop, res.append, str(rootdir))
assert len(res) == 2
res_repr = [ReprOutcome(r) for r in res]
- assert (not res_repr[0].passed and res_repr[1].passed) or \
- (not res_repr[1].passed and res_repr[0].passed)
+ assert not res_repr[0].passed and res_repr[1].passed
def test_slave_run_different_stuff():
node = gettestnode()
@@ -127,7 +129,8 @@
if self.count == 0:
retval = str(tmp)
elif self.count == 1:
- retval = {}
+ from py.__.test.rsession.rsession import remote_options
+ retval = remote_options.d
else:
raise NotImplementedError("mora data")
self.count += 1
@@ -152,7 +155,8 @@
if self.count == 0:
retval = str(x.dirpath())
elif self.count == 1:
- retval = {}
+ from py.__.test.rsession.rsession import remote_options
+ retval = remote_options.d
else:
raise NotImplementedError("mora data")
self.count += 1
From fijal at codespeak.net Mon Nov 13 13:53:18 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 13:53:18 +0100 (CET)
Subject: [py-svn] r34557 - in py/dist/py/test/rsession: . testing
Message-ID: <20061113125318.BCB8D1018E@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 13:53:16 2006
New Revision: 34557
Modified:
py/dist/py/test/rsession/rsession.py
py/dist/py/test/rsession/slave.py
py/dist/py/test/rsession/testing/test_config.py
py/dist/py/test/rsession/testing/test_master.py
py/dist/py/test/rsession/testing/test_rsession.py
Log:
Some fixes of options and some tests for that.
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Mon Nov 13 13:53:16 2006
@@ -62,8 +62,8 @@
ses_opt = self.defaults
for key in self.defaults:
try:
- val = getattr(ses_opt, key)
- except AttributeError:
+ val = ses_opt[key]
+ except KeyError:
val = self.defaults[key]
remote_options[key] = val
Modified: py/dist/py/test/rsession/slave.py
==============================================================================
--- py/dist/py/test/rsession/slave.py (original)
+++ py/dist/py/test/rsession/slave.py Mon Nov 13 13:53:16 2006
@@ -43,7 +43,6 @@
while 1:
nextitem = receive()
if nextitem is None:
- #py.test.Function.state.teardown_all()
break
try:
node = getnode(nextitem)
Modified: py/dist/py/test/rsession/testing/test_config.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_config.py (original)
+++ py/dist/py/test/rsession/testing/test_config.py Mon Nov 13 13:53:16 2006
@@ -3,18 +3,21 @@
"""
import py
-from py.__.test.rsession.rsession import session_options, SessionOptions
+from py.__.test.rsession.rsession import session_options, SessionOptions,\
+ remote_options
def test_session_opts():
tmpdir = py.test.ensuretemp("sessionopts")
tmpdir.ensure("conftest.py").write("""class SessionOptions:
max_tasks_per_node = 5
+ nice_level = 10
""")
tmp2 = py.test.ensuretemp("xxx")
args = [str(tmpdir)]
config, args = py.test.Config.parse(args)
session_options.bind_config(config)
assert session_options.max_tasks_per_node == 5
+ assert remote_options.nice_level == 10
config, args = py.test.Config.parse([str(tmp2)])
session_options.bind_config(config)
assert session_options.max_tasks_per_node == \
Modified: py/dist/py/test/rsession/testing/test_master.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_master.py (original)
+++ py/dist/py/test/rsession/testing/test_master.py Mon Nov 13 13:53:16 2006
@@ -18,6 +18,7 @@
def setup_module(mod):
# bind an empty config
config, args = py.test.Config.parse([])
+ config.options.max_tasks_per_node = 10
session_options.bind_config(config)
#assert not remote_options.exitfirst
mod.pkgdir = py.path.local(py.__file__).dirpath()
Modified: py/dist/py/test/rsession/testing/test_rsession.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_rsession.py (original)
+++ py/dist/py/test/rsession/testing/test_rsession.py Mon Nov 13 13:53:16 2006
@@ -279,6 +279,29 @@
assert len(passed) == 2 * len(nodes)
assert len(skipped) == 0
assert len(events) == len(passed)
+
+ def test_nice_level(self):
+ """ Tests if nice level behaviour is ok
+ """
+ allevents = []
+ hosts = ['localhost']
+ tmpdir = py.test.ensuretemp("nice")
+ tmpdir.ensure("__init__.py")
+ tmpdir.ensure("conftest.py").write("""disthosts = ['localhost']""")
+ tmpdir.ensure("test_one.py").write("""def test_nice():
+ import os
+ assert os.nice(0) == 10
+ """)
+
+ config, args = py.test.Config.parse([str(tmpdir)])
+ config.option.nice_level = 10
+ rsession = RSession(config)
+ allevents = []
+ rsession.main(args, reporter=allevents.append)
+ testevents = [x for x in allevents
+ if isinstance(x, report.ReceivedItemOutcome)]
+ passevents = [x for x in testevents if x.outcome.passed]
+ assert len(passevents) == 1
class TestDirectories(object):
def test_simple_parse(self):
From fijal at codespeak.net Mon Nov 13 14:00:19 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 14:00:19 +0100 (CET)
Subject: [py-svn] r34558 - py/dist/py/documentation
Message-ID: <20061113130019.06DA410193@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 14:00:17 2006
New Revision: 34558
Modified:
py/dist/py/documentation/test.txt
Log:
Updated documentation a bit.
Modified: py/dist/py/documentation/test.txt
==============================================================================
--- py/dist/py/documentation/test.txt (original)
+++ py/dist/py/documentation/test.txt Mon Nov 13 14:00:17 2006
@@ -733,20 +733,29 @@
The options are:
-* disthosts - a list of ssh addresses (including a specific path if it
+* `disthosts` - a list of ssh addresses (including a specific path if it
should be different than the default: ``$HOME/pytestcache-hostname``)
-* distrsync_roots - a list of packages to copy to the remote machines.
-* dist_remotepython - the remote python to run.
+* `distrsync_roots` - a list of packages to copy to the remote machines.
+* `dist_remotepython` - the remote python to run.
+* `SessionOptions` - containing some specific tuning options
Sample configuration::
disthosts = ['localhost', 'user at someserver:/tmp/somedir']
distrsync_roots = ['pypy', 'py']
dist_remotepython = 'python2.4'
+ class SessionOptions:
+ nice_level = 10
Running server is done by ``-w`` command line option or ``--startserver``
(the former might change at some point due to conflicts).
+Possible `SessionOptions` arguments:
+
+* `nice_level` - Level of nice under which tests are run
+* `runner_policy` - (for `LSession` only) - contains policy for the test boxig.
+ `"plain_runner"` means no boxing, `"box_runner"` means boxing.
+
Development Notes
-----------------
From fijal at codespeak.net Mon Nov 13 17:02:17 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 17:02:17 +0100 (CET)
Subject: [py-svn] r34572 - py/dist/py/test/rsession/testing
Message-ID: <20061113160217.C1D09101B0@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 17:02:15 2006
New Revision: 34572
Modified:
py/dist/py/test/rsession/testing/test_master.py
py/dist/py/test/rsession/testing/test_web.py
Log:
Fixed tests.
Modified: py/dist/py/test/rsession/testing/test_master.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_master.py (original)
+++ py/dist/py/test/rsession/testing/test_master.py Mon Nov 13 17:02:15 2006
@@ -18,7 +18,7 @@
def setup_module(mod):
# bind an empty config
config, args = py.test.Config.parse([])
- config.options.max_tasks_per_node = 10
+ config.option.max_tasks_per_node = 10
session_options.bind_config(config)
#assert not remote_options.exitfirst
mod.pkgdir = py.path.local(py.__file__).dirpath()
Modified: py/dist/py/test/rsession/testing/test_web.py
==============================================================================
--- py/dist/py/test/rsession/testing/test_web.py (original)
+++ py/dist/py/test/rsession/testing/test_web.py Mon Nov 13 17:02:15 2006
@@ -15,8 +15,8 @@
py.test.skip("No PyPy detected")
def test_js_generate():
- py.test.skip("XXX")
from py.__.test.rsession import webjs
from py.__.test.rsession.web import FUNCTION_LIST
source = rpython2javascript(webjs, FUNCTION_LIST, Options)
+ assert source
From fijal at codespeak.net Mon Nov 13 17:02:43 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 17:02:43 +0100 (CET)
Subject: [py-svn] r34574 - py/dist/py/test/rsession
Message-ID: <20061113160243.170CA101B7@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 17:02:41 2006
New Revision: 34574
Modified:
py/dist/py/test/rsession/outcome.py
py/dist/py/test/rsession/reporter.py
Log:
Added short/no traceback outcome.
Modified: py/dist/py/test/rsession/outcome.py
==============================================================================
--- py/dist/py/test/rsession/outcome.py (original)
+++ py/dist/py/test/rsession/outcome.py Mon Nov 13 17:02:41 2006
@@ -7,6 +7,7 @@
# internal bug.
import sys
+import py
class Outcome(object):
def __init__(self, setupfailure=False, excinfo=None, skipped=None,
@@ -31,7 +32,10 @@
relline = lineno - tb_entry.frame.code.firstlineno
path = str(tb_entry.path)
try:
- source = str(tb_entry.getsource())
+ if py.test.remote.tbstyle == 'long':
+ source = str(tb_entry.getsource())
+ else:
+ source = str(tb_entry.getsource()).split("\n")[relline]
except:
source = ""
return (relline, lineno, source, path)
Modified: py/dist/py/test/rsession/reporter.py
==============================================================================
--- py/dist/py/test/rsession/reporter.py (original)
+++ py/dist/py/test/rsession/reporter.py Mon Nov 13 17:02:41 2006
@@ -115,8 +115,7 @@
self.out.line("empty traceback from item %r" % (item,))
return
#handler = getattr(self, 'repr_failure_tb%s' % self.config.option.tbstyle)
- handler = self.repr_failure_tblong
- handler(item, excinfo, traceback)
+ self.repr_traceback(item, excinfo, traceback)
if outcome.stdout:
self.out.sep('-', " Captured process stdout: ")
self.out.write(outcome.stdout)
@@ -134,11 +133,16 @@
self.out.sep('-', " Captured process stderr: ")
self.out.write(outcome.stderr)
- def repr_failure_tblong(self, item, excinfo, traceback):
- for index, entry in py.builtin.enumerate(traceback):
- self.out.sep('-')
- self.out.line("%s: %s" % (entry.path, entry.lineno))
- self.repr_source(entry.relline, str(entry.source))
+ def repr_traceback(self, item, excinfo, traceback):
+ if self.config.option.tbstyle == 'long':
+ for index, entry in py.builtin.enumerate(traceback):
+ self.out.sep('-')
+ self.out.line("%s: %s" % (entry.path, entry.lineno))
+ self.repr_source(entry.relline, str(entry.source))
+ elif self.config.option.tbstyle == 'short':
+ for index, entry in py.builtin.enumerate(traceback):
+ self.out.line("%s: %s" % (entry.path, entry.lineno))
+ self.out.line(entry.source)
self.out.line("%s: %s" % (excinfo.typename, excinfo.value))
def repr_source(self, relline, source):
From fijal at codespeak.net Mon Nov 13 19:34:34 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 19:34:34 +0100 (CET)
Subject: [py-svn] r34577 - py/dist/py/test
Message-ID: <20061113183434.716DD101AD@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 19:34:32 2006
New Revision: 34577
Modified:
py/dist/py/test/collect.py
Log:
Add generic __ne__.
Modified: py/dist/py/test/collect.py
==============================================================================
--- py/dist/py/test/collect.py (original)
+++ py/dist/py/test/collect.py Mon Nov 13 19:34:32 2006
@@ -101,6 +101,9 @@
return self.name == other.name and self.parent == other.parent
except AttributeError:
return False
+
+ def __ne__(self, other):
+ return not self == other
def __cmp__(self, other):
s1 = self.getsortvalue()
From fijal at codespeak.net Mon Nov 13 19:55:08 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 19:55:08 +0100 (CET)
Subject: [py-svn] r34578 - in py/dist/py: . apigen/tracer path test/rsession
Message-ID: <20061113185508.9325D101B5@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 19:55:04 2006
New Revision: 34578
Modified:
py/dist/py/apigen/tracer/description.py
py/dist/py/conftest.py
py/dist/py/path/common.py
py/dist/py/test/rsession/rsession.py
Log:
Moved rest generation out of py.test into conftest. This is now local to pylib.
Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py (original)
+++ py/dist/py/apigen/tracer/description.py Mon Nov 13 19:55:04 2006
@@ -253,15 +253,23 @@
self.old_dict = self.perform_dict_copy(obj.__dict__)
def perform_dict_copy(self, d):
+ #try:
+ # c = copy.deepcopy(d)
+ #except:
+ # c = {}
+ # for k, v in d.iteritems():
+ # try:
+ # c[k] = copy.deepcopy(v)
+ # except:
+ # c[k] = v
+ #return c
try:
- c = copy.deepcopy(d)
- except:
c = {}
for k, v in d.iteritems():
- try:
- c[k] = copy.deepcopy(v)
- except:
- c[k] = v
+ c[k] = v
+ except:
+ # cannot perform this
+ c = d
return c
def consider_end_locals(self, frame):
Modified: py/dist/py/conftest.py
==============================================================================
--- py/dist/py/conftest.py (original)
+++ py/dist/py/conftest.py Mon Nov 13 19:55:04 2006
@@ -24,3 +24,14 @@
action="store", dest="sshtarget", default=None,
help="target to run tests requiring ssh, e.g. user at codespeak.net"),
)
+
+class ApiGen:
+ def get_doc_storage():
+ from py.__.apigen.tracer.docstorage import DocStorage
+ return DocStorage().from_pkg(py)
+ get_doc_storage = staticmethod(get_doc_storage)
+
+ def write_docs(ds):
+ from py.__.apigen.rest.genrest import DirectPaste, RestGen, DirWriter
+ RestGen(ds, DirectPaste(), DirWriter("/tmp/output")).write()
+ write_docs = staticmethod(write_docs)
Modified: py/dist/py/path/common.py
==============================================================================
--- py/dist/py/path/common.py (original)
+++ py/dist/py/path/common.py Mon Nov 13 19:55:04 2006
@@ -124,10 +124,12 @@
"""
if not isinstance(relpath, (str, PathBase)):
raise TypeError("%r: not a string or path object" %(relpath,))
- strrelpath = str(relpath)
- if strrelpath and strrelpath[-1] != self.sep:
- strrelpath += self.sep
- strself = str(self)
+ strrelpath = str(relpath)
+ if strrelpath and strrelpath[-1] != self.sep:
+ strrelpath += self.sep
+ #assert strrelpath[-1] == self.sep
+ #assert strrelpath[-2] != self.sep
+ strself = str(self)
if strself.startswith(strrelpath):
return strself[len(strrelpath):]
return ""
Modified: py/dist/py/test/rsession/rsession.py
==============================================================================
--- py/dist/py/test/rsession/rsession.py (original)
+++ py/dist/py/test/rsession/rsession.py Mon Nov 13 19:55:04 2006
@@ -237,12 +237,15 @@
session_options.bind_config(self.config)
if runner is None and self.config.option.apigen:
- from py.__.apigen.tracer.docstorage import DocStorage
from py.__.apigen.tracer.tracer import Tracer
# XXX
module = py
#module = __import__(str(pkgdir.join('__init__.py')))
- self.docstorage = DocStorage().from_pkg(module)
+ try:
+ self.docstorage = self.config.getinitialvalue('ApiGen').get_doc_storage()
+ except (ValueError, AttributeError):
+ raise NotImplementedError("Need to provide conftest "
+ "way of generating DocStorage")
self.tracer = Tracer(self.docstorage)
runner = apigen_runner
#elif runner is None and (self.config.option.usepdb or self.config.option.nocapture):
@@ -275,6 +278,8 @@
py.magic.revoke(assertion=1)
if self.config.option.apigen:
- from py.__.apigen.rest.genrest import DirectPaste, RestGen, DirWriter
- RestGen(self.docstorage, DirectPaste(), DirWriter("/tmp/output")).write()
-
+ try:
+ self.config.getinitialvalue('ApiGen').write_docs(self.docstorage)
+ except ValueError:
+ raise NotImplementedError("Cannot create docs - didn't "
+ "provided way of doing that in conftest")
From fijal at codespeak.net Mon Nov 13 19:59:39 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 19:59:39 +0100 (CET)
Subject: [py-svn] r34579 - py/dist/py/apigen/tracer
Message-ID: <20061113185939.90981101B9@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 19:59:38 2006
New Revision: 34579
Modified:
py/dist/py/apigen/tracer/description.py
Log:
Get rid of very-bare except.
Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py (original)
+++ py/dist/py/apigen/tracer/description.py Mon Nov 13 19:59:38 2006
@@ -267,6 +267,8 @@
c = {}
for k, v in d.iteritems():
c[k] = v
+ except (KeyboardInterrupt, SystemExit):
+ raise
except:
# cannot perform this
c = d
From fijal at codespeak.net Mon Nov 13 20:45:17 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 20:45:17 +0100 (CET)
Subject: [py-svn] r34580 - in py/dist/py/apigen/tracer: . testing
Message-ID: <20061113194517.1B7CD101BC@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 20:45:15 2006
New Revision: 34580
Modified:
py/dist/py/apigen/tracer/description.py
py/dist/py/apigen/tracer/docstorage.py
py/dist/py/apigen/tracer/testing/test_docgen.py
Log:
Added some heuristics which generate a bit more acurate info.
Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py (original)
+++ py/dist/py/apigen/tracer/description.py Mon Nov 13 20:45:15 2006
@@ -106,6 +106,8 @@
return self.code is other.code
if isinstance(other, types.CodeType):
return self.code is other
+ if isinstance(other, tuple) and len(other) == 2:
+ return self.code == other
return False
def __ne__(self, other):
@@ -186,10 +188,10 @@
except: # XXX UUuuuu bare except here. What can it really rise???
try:
hash(self.pyobj)
- return self.pyobj
+ result = self.pyobj
except:
- return self
- return result
+ result = self
+ return (result, self.pyobj)
code = property(getcode)
def consider_call(self, inputcells):
@@ -204,10 +206,14 @@
pass # we *know* what return value we do have
def consider_start_locals(self, frame):
- pass
+ if '__init__' in self.fields:
+ md = self.fields['__init__']
+ md.consider_start_locals(frame)
def consider_end_locals(self, frame):
- pass
+ if '__init__' in self.fields:
+ md = self.fields['__init__']
+ md.consider_end_locals(frame)
def consider_call_site(self, frame, cut_frame):
self.fields['__init__'].consider_call_site(frame, cut_frame)
Modified: py/dist/py/apigen/tracer/docstorage.py
==============================================================================
--- py/dist/py/apigen/tracer/docstorage.py (original)
+++ py/dist/py/apigen/tracer/docstorage.py Mon Nov 13 20:45:15 2006
@@ -17,7 +17,7 @@
"""
def consider_call(self, frame, caller_frame, upward_cut_frame=None):
assert isinstance(frame, py.code.Frame)
- desc = self.find_desc(frame.code)
+ desc = self.find_desc(frame.code, frame.raw.f_locals)
if desc:
self.generalize_args(desc, frame)
desc.consider_call_site(caller_frame, upward_cut_frame)
@@ -33,13 +33,18 @@
def consider_return(self, frame, arg):
assert isinstance(frame, py.code.Frame)
- desc = self.find_desc(frame.code)
+ desc = self.find_desc(frame.code, frame.raw.f_locals)
if desc:
self.generalize_retval(desc, arg)
desc.consider_end_locals(frame)
- def find_desc(self, code):
- return self.desc_cache.get(code.raw, None)
+ def find_desc(self, code, locals):
+ if code.name == '__init__':
+ # argh, very fragile specialcasing
+ key = (code.raw, locals[code.raw.co_varnames[0]].__class__)
+ else:
+ key = code.raw
+ return self.desc_cache.get(key, None)
#for desc in self.descs.values():
# if desc.has_code(frame.code.raw):
# return desc
Modified: py/dist/py/apigen/tracer/testing/test_docgen.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_docgen.py (original)
+++ py/dist/py/apigen/tracer/testing/test_docgen.py Mon Nov 13 20:45:15 2006
@@ -177,3 +177,20 @@
desc = ds.descs['testclass']
methdesc = desc.fields['bar']
assert methdesc.get_local_changes() == {}
+
+def test_multiple_classes_with_same_init():
+ class A:
+ def __init__(self, x):
+ self.x = x
+
+ class B(A):
+ pass
+
+ ds = DocStorage().from_dict({'A':A, 'B':B})
+ t = Tracer(ds)
+ t.start_tracing()
+ c = A(3)
+ d = B(4)
+ t.end_tracing()
+ assert len(ds.descs['A'].fields['__init__'].call_sites) == 1
+ assert len(ds.descs['B'].fields['__init__'].call_sites) == 1
From fijal at codespeak.net Mon Nov 13 22:37:51 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Mon, 13 Nov 2006 22:37:51 +0100 (CET)
Subject: [py-svn] r34588 - py/dist/py/apigen/tracer
Message-ID: <20061113213751.8F061101C8@code0.codespeak.net>
Author: fijal
Date: Mon Nov 13 22:37:49 2006
New Revision: 34588
Modified:
py/dist/py/apigen/tracer/tracer.py
Log:
Fixed stuff for greenlets.
Modified: py/dist/py/apigen/tracer/tracer.py
==============================================================================
--- py/dist/py/apigen/tracer/tracer.py (original)
+++ py/dist/py/apigen/tracer/tracer.py Mon Nov 13 22:37:49 2006
@@ -30,9 +30,12 @@
frame = py.code.Frame(frame)
if event == 'call':
assert arg is None
- self.docstorage.consider_call(frame,
+ try:
+ self.docstorage.consider_call(frame,
py.code.Frame(sys._getframe(2)),
self.frame)
+ except ValueError:
+ self.docstorage.consider_call(frame, None, self.frame)
elif event == 'return':
self.docstorage.consider_return(frame, arg)
return self._tracer
From fijal at codespeak.net Tue Nov 14 00:30:02 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Tue, 14 Nov 2006 00:30:02 +0100 (CET)
Subject: [py-svn] r34590 - py/dist/py/apigen/rest/testing
Message-ID: <20061113233002.3AC59100CC@code0.codespeak.net>
Author: fijal
Date: Tue Nov 14 00:30:01 2006
New Revision: 34590
Modified:
py/dist/py/apigen/rest/testing/test_rest.py
Log:
Fixed test, which was actually broken.
Modified: py/dist/py/apigen/rest/testing/test_rest.py
==============================================================================
--- py/dist/py/apigen/rest/testing/test_rest.py (original)
+++ py/dist/py/apigen/rest/testing/test_rest.py Tue Nov 14 00:30:01 2006
@@ -181,8 +181,8 @@
'method_SomeSubClass.method.txt',
'module_Unknown module.txt',
'traceback_SomeClass.__init__.0.txt',
- 'traceback_SomeClass.__init__.1.txt',
'traceback_SomeClass.method.0.txt',
+ 'traceback_SomeSubClass.__init__.0.txt',
'traceback_fun.0.txt',
'traceback_fun.1.txt',
]
@@ -211,7 +211,7 @@
'module_somemodule.txt',
'module_someothermodule.txt',
'traceback_somemodule.SomeClass.__init__.0.txt',
- 'traceback_somemodule.SomeClass.__init__.1.txt',
+ 'traceback_someothermodule.SomeSubClass.__init__.0.txt',
'traceback_someothermodule.SomeSubClass.method.0.txt',
'traceback_someothermodule.fun.0.txt',
'traceback_someothermodule.fun.1.txt',
From fijal at codespeak.net Tue Nov 14 10:50:06 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Tue, 14 Nov 2006 10:50:06 +0100 (CET)
Subject: [py-svn] r34591 - in py/dist/py/apigen/tracer: . testing
Message-ID: <20061114095006.3B11D101D0@code0.codespeak.net>
Author: fijal
Date: Tue Nov 14 10:50:03 2006
New Revision: 34591
Modified:
py/dist/py/apigen/tracer/description.py
py/dist/py/apigen/tracer/docstorage.py
py/dist/py/apigen/tracer/testing/test_docgen.py
py/dist/py/apigen/tracer/tracer.py
Log:
Added exception handling code.
Modified: py/dist/py/apigen/tracer/description.py
==============================================================================
--- py/dist/py/apigen/tracer/description.py (original)
+++ py/dist/py/apigen/tracer/description.py Tue Nov 14 10:50:03 2006
@@ -124,6 +124,7 @@
self.keep_frames = kwargs.get('keep_frames', False)
self.frame_copier = kwargs.get('frame_copier', lambda x:x)
self.retval = model.s_ImpossibleValue
+ self.exceptions = {}
def consider_call(self, inputcells):
for cell_num, cell in enumerate(inputcells):
@@ -136,6 +137,9 @@
cs = cut_stack(stack, frame, cut_frame)
self.call_sites[cs] = cs
+ def consider_exception(self, exc, value):
+ self.exceptions[exc] = True
+
def get_call_sites(self):
# convinient accessor for various data which we keep there
if not self.keep_frames:
@@ -204,6 +208,14 @@
def consider_return(self, arg):
pass # we *know* what return value we do have
+
+ def consider_exception(self, exc, value):
+ if '__init__' in self.fields:
+ md = self.fields['__init__']
+ else:
+ md = MethodDesc(self.name + '.__init__', self.pyobj.__init__)
+ self.fields['__init__'] = md
+ md.consider_exception(exc, value)
def consider_start_locals(self, frame):
if '__init__' in self.fields:
Modified: py/dist/py/apigen/tracer/docstorage.py
==============================================================================
--- py/dist/py/apigen/tracer/docstorage.py (original)
+++ py/dist/py/apigen/tracer/docstorage.py Tue Nov 14 10:50:03 2006
@@ -37,6 +37,12 @@
if desc:
self.generalize_retval(desc, arg)
desc.consider_end_locals(frame)
+
+ def consider_exception(self, frame, arg):
+ desc = self.find_desc(frame.code, frame.raw.f_locals)
+ if desc:
+ exc_class, value, _ = arg
+ desc.consider_exception(exc_class, value)
def find_desc(self, code, locals):
if code.name == '__init__':
Modified: py/dist/py/apigen/tracer/testing/test_docgen.py
==============================================================================
--- py/dist/py/apigen/tracer/testing/test_docgen.py (original)
+++ py/dist/py/apigen/tracer/testing/test_docgen.py Tue Nov 14 10:50:03 2006
@@ -194,3 +194,25 @@
t.end_tracing()
assert len(ds.descs['A'].fields['__init__'].call_sites) == 1
assert len(ds.descs['B'].fields['__init__'].call_sites) == 1
+
+def test_exception_raise():
+ def x():
+ 1/0
+
+ def y():
+ try:
+ x()
+ except ZeroDivisionError:
+ pass
+
+ def z():
+ y()
+
+ ds = DocStorage().from_dict({'x':x, 'y':y, 'z':z})
+ t = Tracer(ds)
+ t.start_tracing()
+ z()
+ t.end_tracing()
+ assert ds.descs['x'].exceptions.keys() == [ZeroDivisionError]
+ assert ds.descs['y'].exceptions.keys() == [ZeroDivisionError]
+ assert ds.descs['z'].exceptions.keys() == []
Modified: py/dist/py/apigen/tracer/tracer.py
==============================================================================
--- py/dist/py/apigen/tracer/tracer.py (original)
+++ py/dist/py/apigen/tracer/tracer.py Tue Nov 14 10:50:03 2006
@@ -38,6 +38,8 @@
self.docstorage.consider_call(frame, None, self.frame)
elif event == 'return':
self.docstorage.consider_return(frame, arg)
+ elif event == 'exception':
+ self.docstorage.consider_exception(frame, arg)
return self._tracer
def start_tracing(self):
From fijal at codespeak.net Tue Nov 14 10:58:03 2006
From: fijal at codespeak.net (fijal at codespeak.net)
Date: Tue, 14 Nov 2006 10:58:03 +0100 (CET)
Subject: [py-svn] r34592 - in py/dist/py/apigen: rest rest/testing tracer
Message-ID: <20061114095803.02C39101D2@code0.codespeak.net>
Author: fijal
Date: Tue Nov 14 10:58:01 2006
New Revision: 34592
Modified:
py/dist/py/apigen/rest/genrest.py
py/dist/py/apigen/rest/testing/test_rest.py
py/dist/py/apigen/tracer/docstorage.py
Log:
Added generation of exception info into rest.
Modified: py/dist/py/apigen/rest/genrest.py
==============================================================================
--- py/dist/py/apigen/rest/genrest.py (original)
+++ py/dist/py/apigen/rest/genrest.py Tue Nov 14 10:58:01 2006
@@ -335,6 +335,11 @@
for k, changeset in local_changes.iteritems():
lst.append(ListItem('%s: %s' % (k, ', '.join(changeset))))
+ lst.append(Paragraph('Exceptions that might appear in function body:'))
+ for exc in self.dsa.get_function_exceptions(functionname):
+ lst.append(ListItem(exc.__name__))
+ # XXX: right now we leave it alone
+
# XXX missing implementation of dsa.get_function_location()
#filename, lineno = self.dsa.get_function_location(functionname)
#linkname, linktarget = self.linkgen.getlink(filename, lineno)
Modified: py/dist/py/apigen/rest/testing/test_rest.py
==============================================================================
--- py/dist/py/apigen/rest/testing/test_rest.py (original)
+++ py/dist/py/apigen/rest/testing/test_rest.py Tue Nov 14 10:58:01 2006
@@ -346,3 +346,23 @@
assert call_point != -1
assert source.find("x \:\: ") < call_point
self.check_rest(tempdir)
+
+ def test_exc_raising(self):
+ def x():
+ try:
+ 1/0
+ except:
+ pass
+
+ descs = {'x':x}
+ ds = DocStorage().from_dict(descs)
+ t = Tracer(ds)
+ t.start_tracing()
+ x()
+ t.end_tracing()
+ lg = DirectPaste()
+ tempdir = temppath.ensure("exc_raising", dir=True)
+ r = RestGen(ds, lg, DirWriter(tempdir))
+ r.write()
+ source = tempdir.join('function_x.txt').open().read()
+ assert source.find('ZeroDivisionError') < source.find('Call sites\:')
Modified: py/dist/py/apigen/tracer/docstorage.py
==============================================================================
--- py/dist/py/apigen/tracer/docstorage.py (original)
+++ py/dist/py/apigen/tracer/docstorage.py Tue Nov 14 10:58:01 2006
@@ -251,3 +251,6 @@
except AttributeError:
pass
return retval
+
+ def get_function_exceptions(self, name):
+ return sorted(self.ds.descs[name].exceptions.keys())
From guido at codespeak.net Tue Nov 14 13:54:05 2006
From: guido at codespeak.net (guido at codespeak.net)
Date: Tue, 14 Nov 2006 13:54:05 +0100 (CET)
Subject: [py-svn] r34595 - in py/dist/py/rst: . testing
Message-ID: <20061114125405.33F95101B6@code0.codespeak.net>
Author: guido
Date: Tue Nov 14 13:54:03 2006
New Revision: 34595
Modified:
py/dist/py/rst/rst.py
py/dist/py/rst/testing/test_rst.py
Log:
Added support for ReST directives (code I wrote on the sprint and during the
train ride back), changed LiteralBlock so it subclasses from AbstractText
(no need to allow anything but plain text in there, only makes it harder),
added support for nested lists.
Modified: py/dist/py/rst/rst.py
==============================================================================
--- py/dist/py/rst/rst.py (original)
+++ py/dist/py/rst/rst.py Tue Nov 14 13:54:03 2006
@@ -34,6 +34,8 @@
class_list = [parent_cls]
else:
class_list = parent_cls
+ if obj.allow_nesting:
+ class_list.append(obj)
for _class in class_list:
if not _class.allowed_child:
@@ -49,6 +51,7 @@
__metaclass__ = AbstractMetaclass
parentclass = None # this exists to allow parent to know what
# children can exist
+ allow_nesting = False
allowed_child = {}
defaults = {}
@@ -185,16 +188,6 @@
class SubParagraph(Paragraph):
indent = " "
-class LiteralBlock(Paragraph):
- indent = " "
- sep = ""
-
- def text(self):
- all_txt = AbstractNode.text(self)
- all_txts = all_txt.split('\n')
- return '::\n\n%s' % ("\n".join([self.indent + i for i in
- all_txts]),)
-
class Title(Paragraph):
parentclass = Rest
belowchar = ""
@@ -233,6 +226,18 @@
text = escape(self._text)
return self._reg_whitespace.split(text)
+class LiteralBlock(AbstractText):
+ parentclass = Rest
+ start = '::\n\n'
+
+ def text(self):
+ text = self.escape(self._text).split('\n')
+ print text
+ for i, line in enumerate(text):
+ if line.strip():
+ text[i] = ' %s' % (line,)
+ return self.start + '\n'.join(text)
+
class Em(AbstractText):
start = "*"
end = "*"
@@ -258,25 +263,43 @@
raise NotImplemented('XXX')
class ListItem(Paragraph):
- item_char = "*"
+ allow_nesting = True
+ item_chars = '*+-'
def text(self):
- oldindent = self.indent
- self.indent = oldindent + ' '
- try:
- txt = Paragraph.text(self)
- finally:
- self.indent = oldindent
- txt = self.item_char + txt[1:]
- return txt
+ idepth = self.get_indent_depth()
+ indent = self.indent + (idepth + 1) * ' '
+ txt = []
+ for child in self.children:
+ if isinstance(child, AbstractText):
+ p = Paragraph(child, indent=indent)
+ txt.append(p.text())
+ else:
+ txt.append(child.text())
+ txt = '\n'.join(txt)
+ ret = []
+ if idepth:
+ ret.append('\n')
+ item_char = self.item_chars[idepth]
+ ret += [indent[2:], item_char, ' ', txt[len(indent):]]
+ print repr(ret)
+ return ''.join(ret)
+
+ def get_indent_depth(self):
+ depth = 0
+ current = self
+ while current.parent is not None:
+ depth += 1
+ current = current.parent
+ return depth - 1
class OrderedListItem(ListItem):
- item_char = "#."
+ item_chars = ("#.",)
class DListItem(ListItem):
- item_char = None
+ item_chars = None
def __init__(self, term, definition, *args, **kwargs):
- self.item_char = '%s\n ' % (term,)
+ self.item_chars = ('%s\n ' % (term,),)
super(DListItem, self).__init__(definition, *args, **kwargs)
class Link(AbstractText):
@@ -307,3 +330,33 @@
def __init__(self, text, **kwargs):
raise NotImplemented('XXX')
+class Directive(Paragraph):
+ indent = ' '
+ def __init__(self, name, *args, **options):
+ self.name = name
+ self.content = options.pop('content', [])
+ children = list(args)
+ super(Directive, self).__init__(*children)
+ self.options = options
+
+ def text(self):
+ # XXX not very pretty...
+ namechunksize = len(self.name) + 2
+ self.children.insert(0, Text('X' * namechunksize))
+ txt = super(Directive, self).text()
+ txt = '.. %s::%s' % (self.name, txt[namechunksize + 3:],)
+ options = '\n'.join([' :%s: %s' % (k, v) for (k, v) in
+ self.options.iteritems()])
+ if options:
+ txt += '\n%s' % (options,)
+
+ if self.content:
+ txt += '\n'
+ for item in self.content:
+ assert item.parentclass == Rest, 'only top-level items allowed'
+ assert not item.indent
+ item.indent = ' '
+ txt += '\n' + item.text()
+
+ return txt
+
Modified: py/dist/py/rst/testing/test_rst.py
==============================================================================
--- py/dist/py/rst/testing/test_rst.py (original)
+++ py/dist/py/rst/testing/test_rst.py Tue Nov 14 13:54:03 2006
@@ -49,7 +49,7 @@
def test_escape_literal():
txt = LiteralBlock('*escape* ``test``').text()
- assert txt == '::\n\n *escape* ``test``'
+ assert txt == '::\n\n *escape* ``test``'
html = checkrest(txt)
assert '>\n*escape* ``test``\n' in html
@@ -153,8 +153,8 @@
::
- def fun():
- some
+ def fun():
+ some
Paragraph
"""
@@ -272,6 +272,18 @@
assert txt == expected
checkrest(txt)
+def test_nested_lists():
+ expected = """\
+* foo
+
+* bar
+
+ + baz
+"""
+ txt = Rest(ListItem('foo'), ListItem('bar', ListItem('baz'))).text()
+ assert txt == expected
+ checkrest(txt)
+
def test_title_following_links_empty_line():
expected = """\
Foo, bar and `baz`_.
@@ -312,3 +324,33 @@
py.test.raises(ValueError, 'Rest(Transition(), Paragraph("foo")).text()')
py.test.raises(ValueError, 'Rest(Paragraph("foo"), Transition()).text()')
+def test_directive_simple():
+ txt = Rest(Directive('image', 'images/foo.png')).text()
+ asse