[py-svn] r10741 - in py/branch/py-collect: . bin c-extension c-extension/greenlet code code/testing documentation execnet magic magic/testing misc misc/testing path/local path/svn path/svn/testing process tool xmlobj xmlobj/testing
hpk at codespeak.net
hpk at codespeak.net
Sat Apr 16 20:36:09 CEST 2005
Author: hpk
Date: Sat Apr 16 20:36:08 2005
New Revision: 10741
Added:
py/branch/py-collect/bin/py.countloc (props changed)
- copied unchanged from r10740, py/dist/py/bin/py.countloc
py/branch/py-collect/code/testing/test_code.py (props changed)
- copied unchanged from r10740, py/dist/py/code/testing/test_code.py
py/branch/py-collect/tool/
- copied from r10740, py/dist/py/tool/
py/branch/py-collect/tool/__init__.py
py/branch/py-collect/tool/utestconvert.py
- copied unchanged from r10740, py/dist/py/tool/utestconvert.py
Modified:
py/branch/py-collect/__init__.py
py/branch/py-collect/bin/_findpy.py
py/branch/py-collect/c-extension/ (props changed)
py/branch/py-collect/c-extension/greenlet/greenlet.c
py/branch/py-collect/c-extension/greenlet/greenlet.h
py/branch/py-collect/c-extension/greenlet/test_remote.py (props changed)
py/branch/py-collect/code/source.py
py/branch/py-collect/code/testing/test_source.py
py/branch/py-collect/documentation/execnet.txt
py/branch/py-collect/documentation/test.txt
py/branch/py-collect/execnet/channel.py
py/branch/py-collect/magic/assertion.py
py/branch/py-collect/magic/invoke.py
py/branch/py-collect/magic/testing/test_assertion.py
py/branch/py-collect/magic/testing/test_invoke.py
py/branch/py-collect/misc/error.py
py/branch/py-collect/misc/testing/test_initpkg.py
py/branch/py-collect/path/local/local.py
py/branch/py-collect/path/svn/svncommon.py
py/branch/py-collect/path/svn/testing/test_urlcommand.py
py/branch/py-collect/path/svn/testing/test_wccommand.py
py/branch/py-collect/path/svn/wccommand.py
py/branch/py-collect/process/cmdexec.py
py/branch/py-collect/xmlobj/html.py
py/branch/py-collect/xmlobj/testing/test_html.py
py/branch/py-collect/xmlobj/visit.py
Log:
remerge the trunk into the branch ...
Modified: py/branch/py-collect/__init__.py
==============================================================================
--- py/branch/py-collect/__init__.py (original)
+++ py/branch/py-collect/__init__.py Sat Apr 16 20:36:08 2005
@@ -56,7 +56,7 @@
# generalized inspection API
'code.compile' : ('./code/source.py', 'compile_'),
'code.Source' : ('./code/source.py', 'Source'),
- 'code.Code' : ('./code/frame.py', 'Code'),
+ 'code.Code' : ('./code/code.py', 'Code'),
'code.Frame' : ('./code/frame.py', 'Frame'),
'code.ExceptionInfo' : ('./code/excinfo.py', 'ExceptionInfo'),
'code.Traceback' : ('./code/traceback2.py', 'Traceback'),
Modified: py/branch/py-collect/bin/_findpy.py
==============================================================================
--- py/branch/py-collect/bin/_findpy.py (original)
+++ py/branch/py-collect/bin/_findpy.py Sat Apr 16 20:36:08 2005
@@ -27,6 +27,6 @@
if not searchpy(abspath(os.curdir)):
if not searchpy(opd(abspath(sys.argv[0]))):
if not searchpy(opd(__file__)):
- raise SystemExit, "Could not find 'py' package!"
+ pass # let's hope it is just on sys.path
import py
Modified: py/branch/py-collect/c-extension/greenlet/greenlet.c
==============================================================================
--- py/branch/py-collect/c-extension/greenlet/greenlet.c (original)
+++ py/branch/py-collect/c-extension/greenlet/greenlet.c Sat Apr 16 20:36:08 2005
@@ -259,10 +259,10 @@
- ts_passaround: NULL if PyErr_Occurred(),
else a tuple of args sent to ts_target (holds a reference)
*/
- int err, recursion_depth;
+ int err;
{ /* save state */
PyThreadState* tstate = PyThreadState_GET();
- recursion_depth = tstate->recursion_depth;
+ ts_current->recursion_depth = tstate->recursion_depth;
ts_current->top_frame = tstate->frame;
}
ts_origin = ts_current;
@@ -273,7 +273,7 @@
}
else {
PyThreadState* tstate = PyThreadState_GET();
- tstate->recursion_depth = recursion_depth;
+ tstate->recursion_depth = ts_target->recursion_depth;
tstate->frame = ts_target->top_frame;
ts_target->top_frame = NULL;
ts_current = ts_target;
@@ -346,6 +346,8 @@
ts_target->stack_start = NULL;
ts_target->stack_stop = (char*) mark;
ts_target->stack_prev = ts_current;
+ ts_target->top_frame = NULL;
+ ts_target->recursion_depth = PyThreadState_GET()->recursion_depth;
err = _PyGreen_switchstack();
/* returns twice!
The 1st time with err=1: we are in the new greenlet
Modified: py/branch/py-collect/c-extension/greenlet/greenlet.h
==============================================================================
--- py/branch/py-collect/c-extension/greenlet/greenlet.h (original)
+++ py/branch/py-collect/c-extension/greenlet/greenlet.h Sat Apr 16 20:36:08 2005
@@ -19,6 +19,7 @@
struct _greenlet* parent;
PyObject* run_info;
struct _frame* top_frame;
+ int recursion_depth;
} PyGreenlet;
extern PyTypeObject PyGreen_Type;
Modified: py/branch/py-collect/code/source.py
==============================================================================
--- py/branch/py-collect/code/source.py (original)
+++ py/branch/py-collect/code/source.py Sat Apr 16 20:36:08 2005
@@ -1,6 +1,8 @@
from __future__ import generators
import sys
import inspect
+import py
+cpy_compile = compile
# DON'T IMPORT PY HERE
@@ -13,18 +15,31 @@
de = kwargs.get('deindent', True)
rstrip = kwargs.get('rstrip', True)
for part in parts:
+ if not part:
+ partlines = []
if isinstance(part, Source):
partlines = part.lines
- elif isinstance(part, str):
- if rstrip:
- part = part.rstrip()
+ elif isinstance(part, (unicode, str)):
partlines = part.split('\n')
+ if rstrip:
+ while partlines:
+ if partlines[-1].strip():
+ break
+ partlines.pop()
else:
partlines = getsource(part, deindent=de).lines
if de:
partlines = deindent(partlines)
lines.extend(partlines)
+ def __eq__(self, other):
+ try:
+ return self.lines == other.lines
+ except AttributeError:
+ if isinstance(other, str):
+ return str(self) == other
+ return False
+
def __getitem__(self, key):
if isinstance(key, int):
return self.lines[key]
@@ -43,14 +58,13 @@
""" return new source object with trailing
and leading blank lines removed.
"""
- for start in range(0, len(self)):
- if not self.lines[start].isspace():
- break
- for end in range(len(self)-1, -1, -1):
- if not self.lines[end].isspace():
- break
+ start, end = 0, len(self)
+ while start < end and not self.lines[start].strip():
+ start += 1
+ while end > start and not self.lines[end-1].strip():
+ end -= 1
source = Source()
- source.lines[:] = self.lines[start:end+1]
+ source.lines[:] = self.lines[start:end]
return source
def putaround(self, before='', after='', indent=' ' * 4):
@@ -64,6 +78,14 @@
newsource.lines = before.lines + lines + after.lines
return newsource
+ def indent(self, indent=' ' * 4):
+ """ return a copy of the source object with
+ all lines indented by the given indent-string.
+ """
+ newsource = Source()
+ newsource.lines = [(indent+line) for line in self.lines]
+ return newsource
+
def getstatement(self, lineno):
""" return Source statement which contains the
given linenumber (counted from 0).
@@ -125,9 +147,6 @@
newsource.lines[:] = deindent(self.lines, offset)
return newsource
- def __len__(self):
- return len(self.lines)
-
def isparseable(self, deindent=True):
""" return True if source is parseable, heuristically
deindenting it by default.
@@ -148,24 +167,25 @@
return "\n".join(self.lines)
def compile(self, filename=None, mode='exec',
- flag=generators.compiler_flag):
+ flag=generators.compiler_flag, dont_inherit=0):
""" return compiled code object. if filename is None
invent an artificial filename which displays
the source/line position of the caller frame.
"""
- if filename is None:
+ if not filename or py.path.local(filename).check(file=0):
frame = sys._getframe(1) # the caller
- filename = '<%s:%d>' % (frame.f_code.co_filename,
- frame.f_lineno)
- source = str(self)+'\n'
+ filename = '%s<%s:%d>' % (filename, frame.f_code.co_filename,
+ frame.f_lineno)
+ source = "\n".join(self.lines) + '\n'
try:
- co = compile(source, filename, mode, flag)
+ co = cpy_compile(source, filename, mode, flag)
except SyntaxError, ex:
# re-represent syntax errors from parsing python strings
- newex = SyntaxError('\n'.join([
- "".join(self.lines[:ex.lineno]),
- " " * ex.offset + '^',
- "syntax error probably generated here: %s" % filename]))
+ msglines = self.lines[:ex.lineno]
+ if ex.offset:
+ msglines.append(" "*ex.offset + '^')
+ msglines.append("syntax error probably generated here: %s" % filename)
+ newex = SyntaxError('\n'.join(msglines))
newex.offset = ex.offset
newex.lineno = ex.lineno
newex.text = ex.text
@@ -173,14 +193,15 @@
else:
co_filename = MyStr(filename)
co_filename.__source__ = self
- return newcode_withfilename(co, co_filename)
+ return py.code.Code(co).new(rec=1, co_filename=co_filename)
+ #return newcode_withfilename(co, co_filename)
#
# public API shortcut functions
#
def compile_(source, filename=None, mode='exec', flags=
- generators.compiler_flag):
+ generators.compiler_flag, dont_inherit=0):
""" compile the given source to a raw code object,
which points back to the source code through
"co_filename.__source__". All code objects
@@ -192,6 +213,13 @@
co = s.compile(filename, mode, flags)
return co
+
+#
+# various helper functions
+#
+class MyStr(str):
+ """ custom string which allows to add attributes. """
+
def getsource(obj, **kwargs):
if hasattr(obj, 'func_code'):
obj = obj.func_code
@@ -200,7 +228,6 @@
try:
fullsource = obj.co_filename.__source__
except AttributeError:
- import inspect
strsrc = inspect.getsource(obj)
assert isinstance(strsrc, str)
return Source(strsrc, **kwargs)
@@ -209,12 +236,6 @@
end = fullsource.getblockend(lineno)
return fullsource[lineno:end+1]
-#
-# various helper functions
-#
-class MyStr(str):
- """ custom string which allows to add attributes. """
-
def deindent(lines, offset=None):
# XXX maybe use the tokenizer to properly handle multiline
# strings etc.pp?
@@ -235,36 +256,3 @@
newlines.append(line)
return newlines
-def newcode(fromcode, **kwargs):
- names = [x for x in dir(fromcode) if x[:3] == 'co_']
- for name in names:
- if name not in kwargs:
- kwargs[name] = getattr(fromcode, name)
- import new
- return new.code(
- kwargs['co_argcount'],
- kwargs['co_nlocals'],
- kwargs['co_stacksize'],
- kwargs['co_flags'],
- kwargs['co_code'],
- kwargs['co_consts'],
- kwargs['co_names'],
- kwargs['co_varnames'],
- kwargs['co_filename'],
- kwargs['co_name'],
- kwargs['co_firstlineno'],
- kwargs['co_lnotab'],
- kwargs['co_freevars'],
- kwargs['co_cellvars'],
- )
-
-def newcode_withfilename(co, co_filename):
- newconstlist = []
- cotype = type(co)
- for c in co.co_consts:
- if isinstance(c, cotype):
- c = newcode_withfilename(c, co_filename)
- newconstlist.append(c)
- return newcode(co, co_consts = tuple(newconstlist),
- co_filename = co_filename)
-
Modified: py/branch/py-collect/code/testing/test_source.py
==============================================================================
--- py/branch/py-collect/code/testing/test_source.py (original)
+++ py/branch/py-collect/code/testing/test_source.py Sat Apr 16 20:36:08 2005
@@ -19,6 +19,11 @@
""", rstrip=True)
assert str(x) == "\n3"
+def test_unicode():
+ x = Source(unicode("4"))
+ assert str(x) == "4"
+
+
def test_source_from_function():
source = py.code.Source(test_source_str_function)
assert str(source).startswith('def test_source_str_function():')
@@ -47,6 +52,26 @@
else:
x = 23"""
+def test_source_putaround():
+ source = Source()
+ source = source.putaround("""
+ if 1:
+ x=1
+ """)
+ assert str(source).strip() == "if 1:\n x=1"
+
+def test_source_strips():
+ source = Source("")
+ assert source == Source()
+ assert str(source) == ''
+ assert source.strip() == source
+
+def test_source_strip_multiline():
+ source = Source()
+ source.lines = ["", " hello", " "]
+ source2 = source.strip()
+ assert source2.lines == [" hello"]
+
def test_syntaxerror_rerepresentation():
ex = py.test.raises(SyntaxError, py.code.compile, 'x x')
assert ex.value.lineno == 1
@@ -84,41 +109,6 @@
l = [x for x in self.source]
assert len(l) == 4
-
-class TestCodeHacks:
- def test_newcode(self):
- from py.__impl__.code.source import newcode
- def f():
- pass
- co_filename = 'hello'
- c = newcode(f.func_code, co_filename=co_filename)
- assert c.co_filename is co_filename
-
- def test_newcode_withfilename(self):
- from py.__impl__.code.source import newcode_withfilename
- source = py.code.Source("""
- def f():
- def g():
- pass
- """)
- co = compile(str(source)+'\n', 'nada', 'exec')
- obj = 'hello'
- newco = newcode_withfilename(co, obj)
- def walkcode(co):
- for x in co.co_consts:
- if isinstance(x, type(co)):
- for y in walkcode(x):
- yield y
- yield co
-
- names = []
- for code in walkcode(newco):
- assert newco.co_filename == obj
- assert newco.co_filename is obj
- names.append(code.co_name)
- assert 'f' in names
- assert 'g' in names
-
class TestSourceParsingAndCompiling:
source = Source("""\
def f(x):
@@ -132,6 +122,11 @@
exec co
assert x == 3
+ def test_compile_unicode(self):
+ co = py.code.compile(unicode('u"\xc3\xa5"', 'utf8'), mode='eval')
+ val = eval(co)
+ assert isinstance(val, unicode)
+
def test_compile_and_getsource_simple(self):
co = py.code.compile("x=3")
exec co
@@ -179,6 +174,9 @@
#print "block", str(block)
assert str(stmt).strip().startswith('assert')
+ def test_offsetless_synerr(self):
+ py.test.raises(SyntaxError, py.code.compile, "lambda a,a: 0", mode='eval')
+
def test_getstartingblock_singleline():
class A:
def __init__(self, *args):
Modified: py/branch/py-collect/documentation/execnet.txt
==============================================================================
--- py/branch/py-collect/documentation/execnet.txt (original)
+++ py/branch/py-collect/documentation/execnet.txt Sat Apr 16 20:36:08 2005
@@ -45,8 +45,8 @@
apps and especially RMI systems you often have to upgrade your
server if you upgrade your client.
-What about Security? Are you completly nuts?
---------------------------------------------
+What about Security? Are you completely nuts?
+---------------------------------------------
We'll talk about that later :-)
@@ -144,8 +144,8 @@
f.close()
"""
# open a gateway to a fresh child process
- contentgateway = py.execnet.SSHGateway('codespeak.net', identity)
- channel = contentgateway.remote_exec_async(contentserverbootstrap)
+ contentgateway = py.execnet.SshGateway('codespeak.net')
+ channel = contentgateway.remote_exec(contentserverbootstrap)
for fn in somefilelist:
channel.send(fn)
Modified: py/branch/py-collect/documentation/test.txt
==============================================================================
--- py/branch/py-collect/documentation/test.txt (original)
+++ py/branch/py-collect/documentation/test.txt Sat Apr 16 20:36:08 2005
@@ -35,9 +35,10 @@
py.test
-This will automatically collect any Python module that starts with
-``test_`` in the whole directory hierarchy, starting with the current
-directory, and run them.
+This will automatically collect and run any Python module whose filenames
+start with ``test_`` from the directory and any subdirectories, starting
+with the current directory, and run them. Each Python test module is
+inspect for test methods starting with ``test_``.
Basic Features of ``py.test``
=============================
@@ -81,14 +82,15 @@
automatic collection of tests on all levels
-------------------------------------------
-The automated test collection process collects files
-from all subdirectories with a leading ``test_`` in their
-filename and then every function with a leading ``test_``
-or ``Test`` in the case of classes. The collecting process
-can be customized at each level. (see `collection process`_
+The automated test collection process walks the current
+directory (or the directory given as a command line argument)
+and all its subdirectories and collects python modules with a
+leading ``test_`` filename. From each test module every function
+with a leading ``test_`` or class with a leading ``Test`` name
+is collected. The collecting process can be customized at
+directory, module or class level. (see `collection process`_
for some implementation details).
-
.. _`generative tests`:
generative tests: yielding more tests
@@ -475,3 +477,61 @@
.. _`getting started`: getting_started.html
.. _`py-dev mailing list`: http://codespeak.net/mailman/listinfo/py-dev
+
+
+Future/Planned Features of py.test
+==================================
+
+Please note that the following descriptions of future features
+sound factual although they aren't implemented yet. This
+allows easy migration to real documentation later.
+Nevertheless, none of the described planned features is
+set in stone, yet. In fact, they are open to discussion on
+py-dev at codespeak dot net.
+
+Hey, if you want to suggest new features or command line options
+for py.test it would be great if you could do it by providing
+documentation for the feature. Welcome to documentation driven
+development :-)
+
+selecting tests by queries/full text search
+-------------------------------------------
+
+You can selectively run tests by specifiying words
+on the command line in a google-like way. Example::
+
+ py.test simple
+
+will run all tests that are found from the current directory
+and that have the word "simple" somewhere in their `test address`_.
+``test_simple1`` and ``TestSomething.test_whatever_simpleton`` would both
+qualify. If you want to exclude the latter test method you could say::
+
+ py.test -- simple -simpleton
+
+Note that the doubledash "--" signals the end of option parsing so
+that "-simpleton" will not be misinterpreted as a command line option.
+
+Interpreting positional arguments as specifying search queries
+means that you can only restrict the set of tests. There is no way to
+say "run all 'simple' in addition to all 'complex' tests". If this proves
+to be a problem we can probably come up with a command line option
+that allows to specify multiple queries which all add to the set of
+tests-to-consider.
+
+.. _`test address`:
+
+the concept of a test address
+-----------------------------
+
+For specifiying tests it is convenient to define the notion
+of a *test address*, representable as a filesystem path and a
+list of names leading to a test item. If represented as a single
+string the path and names are separated by a `/` character, for example:
+
+ ``somedir/somepath.py/TestClass/test_method``
+
+Such representations can be used to memoize failing tests
+by writing them out in a file or communicating them across
+process and computer boundaries.
+
Modified: py/branch/py-collect/execnet/channel.py
==============================================================================
--- py/branch/py-collect/execnet/channel.py (original)
+++ py/branch/py-collect/execnet/channel.py Sat Apr 16 20:36:08 2005
@@ -113,11 +113,13 @@
return x
def __iter__(self):
- while 1:
- try:
- yield self.receive()
- except EOFError:
- raise StopIteration
+ return self
+
+ def next(self):
+ try:
+ return self.receive()
+ except EOFError:
+ raise StopIteration
#
# helpers
Modified: py/branch/py-collect/magic/assertion.py
==============================================================================
--- py/branch/py-collect/magic/assertion.py (original)
+++ py/branch/py-collect/magic/assertion.py Sat Apr 16 20:36:08 2005
@@ -7,20 +7,23 @@
class AssertionError(BuiltinAssertionError):
def __init__(self, *args):
BuiltinAssertionError.__init__(self, *args)
- f = sys._getframe(1)
- try:
- source = py.code.Frame(f).statement
- source = str(source).strip()
- except py.error.ENOENT:
- source = None
- # this can also occur during reinterpretation, when the
- # co_filename is set to "<run>".
- if source:
- self.msg = exprinfo.interpret(source, f, should_fail=True)
- if not self.args:
- self.args = (self.msg,)
- else:
- self.msg = None
+ if args:
+ self.msg = args[0]
+ else:
+ f = sys._getframe(1)
+ try:
+ source = py.code.Frame(f).statement
+ source = str(source).strip()
+ except py.error.ENOENT:
+ source = None
+ # this can also occur during reinterpretation, when the
+ # co_filename is set to "<run>".
+ if source:
+ self.msg = exprinfo.interpret(source, f, should_fail=True)
+ if not self.args:
+ self.args = (self.msg,)
+ else:
+ self.msg = None
def invoke():
py.magic.patch(__builtin__, 'AssertionError', AssertionError)
Modified: py/branch/py-collect/magic/invoke.py
==============================================================================
--- py/branch/py-collect/magic/invoke.py (original)
+++ py/branch/py-collect/magic/invoke.py Sat Apr 16 20:36:08 2005
@@ -1,5 +1,7 @@
+import py
+import __builtin__ as cpy_builtin
-def invoke(assertion=False):
+def invoke(assertion=False, compile=False):
""" invoke magic, currently you can specify:
assertion patches the builtin AssertionError to try to give
@@ -10,10 +12,13 @@
if assertion:
from py.__impl__.magic import assertion
assertion.invoke()
+ if compile:
+ py.magic.patch(cpy_builtin, 'compile', py.code.compile )
-def revoke(assertion=False):
+def revoke(assertion=False, compile=False):
""" revoke previously invoked magic (see invoke())."""
if assertion:
from py.__impl__.magic import assertion
assertion.revoke()
-
+ if compile:
+ py.magic.revert(cpy_builtin, 'compile')
Modified: py/branch/py-collect/magic/testing/test_assertion.py
==============================================================================
--- py/branch/py-collect/magic/testing/test_assertion.py (original)
+++ py/branch/py-collect/magic/testing/test_assertion.py Sat Apr 16 20:36:08 2005
@@ -16,6 +16,12 @@
s = str(e)
assert s.startswith('assert 2 == 3\n')
+def test_assert_with_explicit_message():
+ try:
+ assert f() == 3, "hello"
+ except AssertionError, e:
+ assert e.msg == 'hello'
+
def test_assert_within_finally():
class A:
def f():
Modified: py/branch/py-collect/magic/testing/test_invoke.py
==============================================================================
--- py/branch/py-collect/magic/testing/test_invoke.py (original)
+++ py/branch/py-collect/magic/testing/test_invoke.py Sat Apr 16 20:36:08 2005
@@ -13,3 +13,17 @@
finally:
py.magic.revoke(assertion=True)
+def test_invoke_compile():
+ py.magic.invoke(compile=True)
+ try:
+ co = compile("""if 1:
+ def f():
+ return 1
+ \n""", '', 'exec')
+ d = {}
+ exec co in d
+ assert py.code.Source(d['f'])
+ finally:
+ py.magic.revoke(compile=True)
+
+
Modified: py/branch/py-collect/misc/error.py
==============================================================================
--- py/branch/py-collect/misc/error.py (original)
+++ py/branch/py-collect/misc/error.py Sat Apr 16 20:36:08 2005
@@ -19,7 +19,8 @@
_winerrnomap = {
3: py.std.errno.ENOENT,
- 267: py.std.errno.ENOTDIR,
+ 267: py.std.errno.ENOTDIR,
+ 5: py.std.errno.EACCES, # anything better?
}
ModuleType = type(py)
Modified: py/branch/py-collect/misc/testing/test_initpkg.py
==============================================================================
--- py/branch/py-collect/misc/testing/test_initpkg.py (original)
+++ py/branch/py-collect/misc/testing/test_initpkg.py Sat Apr 16 20:36:08 2005
@@ -44,6 +44,7 @@
base.join('documentation',),
base.join('test', 'testing', 'import_test'),
base.join('c-extension',),
+ base.join('magic', 'greenlet.py'),
base.join('bin'),
base.join('execnet', 'bin'),
)
Modified: py/branch/py-collect/path/local/local.py
==============================================================================
--- py/branch/py-collect/path/local/local.py (original)
+++ py/branch/py-collect/path/local/local.py Sat Apr 16 20:36:08 2005
@@ -59,14 +59,14 @@
path = path.strpath
# initialize the path
self = object.__new__(cls)
- if path is None:
+ if not path:
self.strpath = os.getcwd()
- elif not path:
+ elif isinstance(path, str):
+ self.strpath = os.path.abspath(os.path.normpath(str(path)))
+ else:
raise ValueError(
"can only pass None, Path instances "
"or non-empty strings to LocalPath")
- else:
- self.strpath = os.path.abspath(os.path.normpath(str(path)))
assert isinstance(self.strpath, str)
return self
@@ -422,7 +422,17 @@
if len(header) == 8:
magic, timestamp = py.std.struct.unpack('<4si', header)
if magic == my_magic and timestamp == my_timestamp:
- return py.std.marshal.load(f)
+ co = py.std.marshal.load(f)
+ path1 = co.co_filename
+ path2 = str(self)
+ if path1 == path2:
+ return co
+ try:
+ if os.path.samefile(path1, path2):
+ return co
+ except (OSError, # probably path1 not found
+ AttributeError): # samefile() not available
+ pass
finally:
f.close()
except py.error.Error:
@@ -458,7 +468,7 @@
stdout, stderr,)
return stdout
- def sysfind(self, name, checker=None):
+ def sysfind(cls, name, checker=None):
""" return a path object found by looking at the systems
underlying PATH specification. If the checker is not None
it will be invoked to filter matching paths. If a binary
@@ -503,7 +513,7 @@
dpath = cls(tempfile.mktemp())
try:
dpath.mkdir()
- except path.FileExists:
+ except (py.error.EEXIST, py.error.EPERM, py.error.EACCES):
continue
return dpath
raise py.error.ENOENT(dpath, "could not create tempdir, %d tries" % tries)
Modified: py/branch/py-collect/path/svn/svncommon.py
==============================================================================
--- py/branch/py-collect/path/svn/svncommon.py (original)
+++ py/branch/py-collect/path/svn/svncommon.py Sat Apr 16 20:36:08 2005
@@ -3,7 +3,6 @@
"""
import os, sys, time, re
import py
-from py import path, process
from py.__impl__.path import common
#_______________________________________________________________
Modified: py/branch/py-collect/path/svn/testing/test_urlcommand.py
==============================================================================
--- py/branch/py-collect/path/svn/testing/test_urlcommand.py (original)
+++ py/branch/py-collect/path/svn/testing/test_urlcommand.py Sat Apr 16 20:36:08 2005
@@ -1,5 +1,5 @@
import py
-from svntestbase import CommonCommandAndBindingTests, getrepowc
+from py.__impl__.path.svn.testing.svntestbase import CommonCommandAndBindingTests, getrepowc
class TestSvnCommandPath(CommonCommandAndBindingTests):
def setup_class(cls):
Modified: py/branch/py-collect/path/svn/testing/test_wccommand.py
==============================================================================
--- py/branch/py-collect/path/svn/testing/test_wccommand.py (original)
+++ py/branch/py-collect/path/svn/testing/test_wccommand.py Sat Apr 16 20:36:08 2005
@@ -1,5 +1,5 @@
import py
-from svntestbase import CommonSvnTests, getrepowc
+from py.__impl__.path.svn.testing.svntestbase import CommonSvnTests, getrepowc
class TestWCSvnCommandPath(CommonSvnTests):
Modified: py/branch/py-collect/path/svn/wccommand.py
==============================================================================
--- py/branch/py-collect/path/svn/wccommand.py (original)
+++ py/branch/py-collect/path/svn/wccommand.py Sat Apr 16 20:36:08 2005
@@ -9,7 +9,6 @@
"""
import os, sys, time, re
-from py import path
import py
from py.__impl__.path import common
from py.__impl__.path.svn import cache
@@ -22,7 +21,11 @@
def __new__(cls, wcpath=None):
self = object.__new__(cls)
- self.localpath = path.local(wcpath)
+ if isinstance(wcpath, cls):
+ if wcpath.__class__ == cls:
+ return wcpath
+ wcpath = wcpath.localpath
+ self.localpath = py.path.local(wcpath)
return self
strpath = property(lambda x: str(x.localpath), None, None, "string path")
@@ -43,7 +46,7 @@
def svnurl(self):
""" return current SvnPath for this WC-item. """
info = self.info()
- return path.svnurl(info.url)
+ return py.path.svnurl(info.url)
url = property(_geturl, None, None, "url of this WC item")
@@ -131,6 +134,7 @@
ignored and considered always true (because of
underlying svn semantics.
"""
+ assert rec, "svn cannot remove non-recursively"
flags = []
if force:
flags.append('--force')
@@ -357,14 +361,14 @@
def get(self, spec):
return self.localpath.get(spec)
- class Checkers(path.local.Checkers):
+ class Checkers(py.path.local.Checkers):
def __init__(self, path):
self.svnwcpath = path
self.path = path.localpath
def versioned(self):
try:
s = self.svnwcpath.info()
- except py.error.ENOENT:
+ except (py.error.ENOENT, py.error.EEXIST):
return False
except py.process.cmdexec.Error, e:
if e.err.find('is not a working copy')!=-1:
Modified: py/branch/py-collect/process/cmdexec.py
==============================================================================
--- py/branch/py-collect/process/cmdexec.py (original)
+++ py/branch/py-collect/process/cmdexec.py Sat Apr 16 20:36:08 2005
@@ -79,7 +79,14 @@
Note that this method can currently deadlock because
we don't have WaitForMultipleObjects in the std-python api.
+
+ Further note that the rules for quoting are very special
+ under Windows. Do a HELP CMD in a shell, and tell me if
+ you understand this. For now, I try to do a fix.
"""
+ print "*****", cmd
+ if '"' in cmd and not cmd.startswith('""'):
+ cmd = '"%s"' % cmd
stdin, stdout, stderr = os.popen3(cmd)
out = stdout.read()
err = stderr.read()
Added: py/branch/py-collect/tool/__init__.py
==============================================================================
--- (empty file)
+++ py/branch/py-collect/tool/__init__.py Sat Apr 16 20:36:08 2005
@@ -0,0 +1 @@
+#
Modified: py/branch/py-collect/xmlobj/html.py
==============================================================================
--- py/branch/py-collect/xmlobj/html.py (original)
+++ py/branch/py-collect/xmlobj/html.py Sat Apr 16 20:36:08 2005
@@ -2,16 +2,34 @@
"""
-from py.xml import Namespace
+from py.xml import Namespace, Tag
+from py.__impl__.xmlobj.visit import SimpleUnicodeVisitor
+
+class HtmlVisitor(SimpleUnicodeVisitor):
+ def repr_attribute(self, attrs, name):
+ if name == 'class_':
+ value = getattr(attrs, name)
+ if value is None:
+ return
+ return super(HtmlVisitor, self).repr_attribute(attrs, name)
+
+class HtmlTag(Tag):
+ def unicode(self, indent=2):
+ l = []
+ HtmlVisitor(l.append, indent, shortempty=False).visit(self)
+ return u"".join(l)
# exported plain html namespace
class html(Namespace):
+ __tagclass__ = HtmlTag
__stickyname__ = True
__tagspec__ = dict([(x,1) for x in (
"h1,h2,h3,h5,h6,p,b,i,a,div,span,code,"
"html,head,title,style,table,tr,tt,"
"td,th,link,img,meta,body,pre,br,ul,"
- "ol,li,em,form,input,select,option"
+ "ol,li,em,form,input,select,option,"
+ "button,script,colgroup,col,map,area,"
+ "blockquote,dl,dt,dd,strong"
).split(',') if x])
class Style(object):
Modified: py/branch/py-collect/xmlobj/testing/test_html.py
==============================================================================
--- py/branch/py-collect/xmlobj/testing/test_html.py (original)
+++ py/branch/py-collect/xmlobj/testing/test_html.py Sat Apr 16 20:36:08 2005
@@ -11,7 +11,12 @@
class body(html.body):
style = html.Style(font_size = "12pt")
u = unicode(my.body())
- assert u == '<body style="font-size: 12pt"/>'
+ assert u == '<body style="font-size: 12pt"></body>'
+
+def test_class_None():
+ t = html.body(class_=None)
+ u = unicode(t)
+ assert u == '<body></body>'
def test_alternating_style():
alternating = (
Modified: py/branch/py-collect/xmlobj/visit.py
==============================================================================
--- py/branch/py-collect/xmlobj/visit.py (original)
+++ py/branch/py-collect/xmlobj/visit.py Sat Apr 16 20:36:08 2005
@@ -6,13 +6,14 @@
class SimpleUnicodeVisitor(object):
""" recursive visitor to write unicode. """
- def __init__(self, write, indent=0, curindent=0):
+ def __init__(self, write, indent=0, curindent=0, shortempty=True):
self.write = write
self.cache = {}
self.visited = {} # for detection of recursion
self.indent = indent
self.curindent = curindent
self.parents = []
+ self.shortempty = shortempty # short empty tags or not
def visit(self, node):
""" dispatcher on node's class/bases name. """
@@ -57,7 +58,11 @@
self.write(u'</%s>' % tagname)
self.curindent -= self.indent
else:
- self.write(u'<%s%s/>' % (tagname, self.attributes(tag)))
+ nameattr = tagname+self.attributes(tag)
+ if self.shortempty:
+ self.write(u'<%s/>' % (nameattr,))
+ else:
+ self.write(u'<%s></%s>' % (nameattr, tagname))
def attributes(self, tag):
# serialize attributes
@@ -65,14 +70,19 @@
attrlist.sort()
l = []
for name in attrlist:
- if name[0] != '_':
- value = getattr(tag.attr, name)
- if name.endswith('_'):
- name = name[:-1]
- l.append(u' %s="%s"' % (name, escape(unicode(value))))
+ res = self.repr_attribute(tag.attr, name)
+ if res is not None:
+ l.append(res)
l.extend(self.getstyle(tag))
return u"".join(l)
+ def repr_attribute(self, attrs, name):
+ if name[:2] != '__':
+ value = getattr(attrs, name)
+ if name.endswith('_'):
+ name = name[:-1]
+ return u' %s="%s"' % (name, escape(unicode(value)))
+
def getstyle(self, tag):
""" return attribute list suitable for styling. """
try:
More information about the pytest-commit
mailing list