deprecate py.compat.doctest|subprocess|textwrap|...
(and for now pass through Python stdlib provided modules). --HG-- branch : trunk
This commit is contained in:
parent
681d344eac
commit
d1932a30ed
|
@ -261,7 +261,7 @@ class PluginDoc(RestWriter):
|
||||||
return
|
return
|
||||||
self.h2("command line options")
|
self.h2("command line options")
|
||||||
self.Print()
|
self.Print()
|
||||||
formatter = py.compat.optparse.IndentedHelpFormatter()
|
formatter = py.std.optparse.IndentedHelpFormatter()
|
||||||
for opt in options:
|
for opt in options:
|
||||||
switches = formatter.format_option_strings(opt)
|
switches = formatter.format_option_strings(opt)
|
||||||
self.Print("``%s``" % switches)
|
self.Print("``%s``" % switches)
|
||||||
|
|
|
@ -7,9 +7,8 @@ obtain system info from remote machine.
|
||||||
import py
|
import py
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
optparse = py.compat.optparse
|
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage=__doc__)
|
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||||
parser.add_option("-f", "--sshconfig", action="store", dest="ssh_config", default=None,
|
parser.add_option("-f", "--sshconfig", action="store", dest="ssh_config", default=None,
|
||||||
help="use given ssh config file, and add info all contained hosts for getting info")
|
help="use given ssh config file, and add info all contained hosts for getting info")
|
||||||
parser.add_option("-i", "--ignore", action="store", dest="ignores", default=None,
|
parser.add_option("-i", "--ignore", action="store", dest="ignores", default=None,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
Changes between 1.0.x and 'trunk'
|
Changes between 1.0.x and 'trunk'
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
* deprecate py.compat.doctest|subprocess|textwrap|optparse
|
||||||
|
|
||||||
* deprecate py.magic.autopath, remove py/magic directory
|
* deprecate py.magic.autopath, remove py/magic directory
|
||||||
|
|
||||||
* move pytest assertion handling to py/code and a pytest_assertion
|
* move pytest assertion handling to py/code and a pytest_assertion
|
||||||
|
|
16
doc/misc.txt
16
doc/misc.txt
|
@ -93,26 +93,10 @@ Cross-Python Version compatibility helpers
|
||||||
|
|
||||||
sources:
|
sources:
|
||||||
|
|
||||||
* :source:`py/compat/`
|
|
||||||
* :source:`py/builtin/`
|
* :source:`py/builtin/`
|
||||||
|
|
||||||
The compat and builtin namespaces help to write code using newer python features on older python interpreters.
|
The compat and builtin namespaces help to write code using newer python features on older python interpreters.
|
||||||
|
|
||||||
:api:`py.compat`
|
|
||||||
----------------
|
|
||||||
|
|
||||||
:api:`py.compat` provides fixed versions (currently taken from Python 2.4.4) of
|
|
||||||
a few selected modules to be able to use them across python versions. Currently these are:
|
|
||||||
|
|
||||||
* doctest
|
|
||||||
* optparse
|
|
||||||
* subprocess
|
|
||||||
* textwrap
|
|
||||||
|
|
||||||
Note that for example ``import doctest`` and ``from py.compat import doctest`` result
|
|
||||||
into two different module objects no matter what Python version you are using.
|
|
||||||
So you should only use exactly one of these to avoid confusion in your program.
|
|
||||||
|
|
||||||
:api:`py.builtin`
|
:api:`py.builtin`
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,8 @@ obtain system info from remote machine.
|
||||||
import py
|
import py
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
optparse = py.compat.optparse
|
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage=__doc__)
|
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||||
parser.add_option("-f", "--sshconfig", action="store", dest="ssh_config", default=None,
|
parser.add_option("-f", "--sshconfig", action="store", dest="ssh_config", default=None,
|
||||||
help="use given ssh config file, and add info all contained hosts for getting info")
|
help="use given ssh config file, and add info all contained hosts for getting info")
|
||||||
parser.add_option("-i", "--ignore", action="store", dest="ignores", default=None,
|
parser.add_option("-i", "--ignore", action="store", dest="ignores", default=None,
|
||||||
|
|
|
@ -191,12 +191,12 @@ initpkg(__name__,
|
||||||
'log.STDERR' : ('./log/log.py', 'STDERR'),
|
'log.STDERR' : ('./log/log.py', 'STDERR'),
|
||||||
'log.Syslog' : ('./log/log.py', 'Syslog'),
|
'log.Syslog' : ('./log/log.py', 'Syslog'),
|
||||||
|
|
||||||
# compatibility modules (taken from 2.4.4)
|
# compatibility modules (deprecated)
|
||||||
'compat.__doc__' : ('./compat/__init__.py', '__doc__'),
|
'compat.__doc__' : ('./compat/__init__.py', '__doc__'),
|
||||||
'compat.doctest' : ('./compat/doctest.py', '*'),
|
'compat.doctest' : ('./compat/dep_doctest.py', 'doctest'),
|
||||||
'compat.optparse' : ('./compat/optparse.py', '*'),
|
'compat.optparse' : ('./compat/dep_optparse.py', 'optparse'),
|
||||||
'compat.textwrap' : ('./compat/textwrap.py', '*'),
|
'compat.textwrap' : ('./compat/dep_textwrap.py', 'textwrap'),
|
||||||
'compat.subprocess' : ('./compat/subprocess.py', '*'),
|
'compat.subprocess' : ('./compat/dep_subprocess.py', 'subprocess'),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ a ".".
|
||||||
import py
|
import py
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = py.compat.optparse.OptionParser(usage=__doc__)
|
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||||
parser.add_option("-e", "--remove", dest="ext", default=".pyc", action="store",
|
parser.add_option("-e", "--remove", dest="ext", default=".pyc", action="store",
|
||||||
help="remove files with the given comma-separated list of extensions"
|
help="remove files with the given comma-separated list of extensions"
|
||||||
)
|
)
|
||||||
|
|
|
@ -191,7 +191,7 @@ def main():
|
||||||
import py
|
import py
|
||||||
|
|
||||||
usage = "usage: %prog [-s [filename ...] | [-i | -c filename ...]]"
|
usage = "usage: %prog [-s [filename ...] | [-i | -c filename ...]]"
|
||||||
optparser = py.compat.optparse.OptionParser(usage)
|
optparser = py.std.optparse.OptionParser(usage)
|
||||||
|
|
||||||
def select_output (option, opt, value, optparser, **kw):
|
def select_output (option, opt, value, optparser, **kw):
|
||||||
if hasattr(optparser, 'output'):
|
if hasattr(optparser, 'output'):
|
||||||
|
|
|
@ -12,10 +12,9 @@ current working directory). Distinguish between test files and normal ones and
|
||||||
report them separately.
|
report them separately.
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
from py.compat import optparse
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = optparse.OptionParser(usage=__doc__)
|
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
countloc(args)
|
countloc(args)
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,7 @@ curdir = py.path.local()
|
||||||
def rec(p):
|
def rec(p):
|
||||||
return p.check(dotfile=0)
|
return p.check(dotfile=0)
|
||||||
|
|
||||||
optparse = py.compat.optparse
|
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage=__doc__)
|
|
||||||
parser.add_option("-i", "--ignore-case", action="store_true", dest="ignorecase",
|
parser.add_option("-i", "--ignore-case", action="store_true", dest="ignorecase",
|
||||||
help="ignore case distinctions")
|
help="ignore case distinctions")
|
||||||
parser.add_option("-C", "--context", action="store", type="int", dest="context",
|
parser.add_option("-C", "--context", action="store", type="int", dest="context",
|
||||||
|
|
|
@ -22,9 +22,8 @@ else:
|
||||||
def log(msg):
|
def log(msg):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
optparse = py.compat.optparse
|
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage=__doc__)
|
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||||
parser.add_option("--topdf", action="store_true", dest="topdf", default=False,
|
parser.add_option("--topdf", action="store_true", dest="topdf", default=False,
|
||||||
help="generate pdf files")
|
help="generate pdf files")
|
||||||
parser.add_option("--stylesheet", dest="stylesheet", default=None,
|
parser.add_option("--stylesheet", dest="stylesheet", default=None,
|
||||||
|
|
|
@ -41,9 +41,8 @@ def svnwcrevert(path, root=None, precious=[]):
|
||||||
svnwcrevert(p, root)
|
svnwcrevert(p, root)
|
||||||
|
|
||||||
# XXX add a functional test
|
# XXX add a functional test
|
||||||
optparse = py.compat.optparse
|
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage=__doc__)
|
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||||
parser.add_option("-p", "--precious",
|
parser.add_option("-p", "--precious",
|
||||||
action="append", dest="precious", default=[],
|
action="append", dest="precious", default=[],
|
||||||
help="preserve files with this name")
|
help="preserve files with this name")
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
License for modules in py/compat directory
|
|
||||||
==============================================================
|
|
||||||
|
|
||||||
The "*.py" files in py/compat/ and subdirectories are all
|
|
||||||
- except when otherwise stated at the beginning of the file -
|
|
||||||
copyrighted by the Python Software Foundation and licensed
|
|
||||||
under the Python Software License of which you can find a copy
|
|
||||||
here: http://www.python.org/doc/Copyright.html
|
|
|
@ -1,5 +0,0 @@
|
||||||
import py
|
|
||||||
|
|
||||||
class Directory(py.test.collect.Directory):
|
|
||||||
def collect(self):
|
|
||||||
py.test.skip("compat tests need to be run manually")
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import py
|
||||||
|
|
||||||
|
py.log._apiwarn("1.1", "py.compat.doctest deprecated, use standard library version.", stacklevel="initpkg")
|
||||||
|
doctest = py.std.doctest
|
|
@ -0,0 +1,4 @@
|
||||||
|
import py
|
||||||
|
py.log._apiwarn("1.1", "py.compat.optparse deprecated, use standard library version.", stacklevel="initpkg")
|
||||||
|
|
||||||
|
optparse = py.std.optparse
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
import py
|
||||||
|
py.log._apiwarn("1.1", "py.compat.subprocess deprecated, use standard library version.", stacklevel="initpkg")
|
||||||
|
subprocess = py.std.subprocess
|
|
@ -0,0 +1,4 @@
|
||||||
|
import py
|
||||||
|
|
||||||
|
py.log._apiwarn("1.1", "py.compat.textwrap deprecated, use standard library version.", stacklevel="initpkg")
|
||||||
|
textwrap = py.std.textwrap
|
2672
py/compat/doctest.py
2672
py/compat/doctest.py
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
def test_functional_deprecation(testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import py
|
||||||
|
def test_compat_deprecations(recwarn):
|
||||||
|
for name in 'subprocess optparse textwrap doctest'.split():
|
||||||
|
check(recwarn, name)
|
||||||
|
def check(recwarn, name):
|
||||||
|
x = getattr(py.compat, name)
|
||||||
|
recwarn.pop(DeprecationWarning)
|
||||||
|
recwarn.clear()
|
||||||
|
assert x == getattr(py.std, name)
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest()
|
||||||
|
assert result.ret == 0
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,17 +0,0 @@
|
||||||
This is a sample doctest in a text file.
|
|
||||||
|
|
||||||
In this example, we'll rely on a global variable being set for us
|
|
||||||
already:
|
|
||||||
|
|
||||||
>>> favorite_color
|
|
||||||
'blue'
|
|
||||||
|
|
||||||
We can make this fail by disabling the blank-line feature.
|
|
||||||
|
|
||||||
>>> if 1:
|
|
||||||
... print 'a'
|
|
||||||
... print
|
|
||||||
... print 'b'
|
|
||||||
a
|
|
||||||
<BLANKLINE>
|
|
||||||
b
|
|
|
@ -1,122 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
u"""A module to test whether doctest recognizes some 2.2 features,
|
|
||||||
like static and class methods.
|
|
||||||
|
|
||||||
>>> print 'yup' # 1
|
|
||||||
yup
|
|
||||||
|
|
||||||
We include some (random) encoded (utf-8) text in the text surrounding
|
|
||||||
the example. It should be ignored:
|
|
||||||
|
|
||||||
ЉЊЈЁЂ
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from test import test_support
|
|
||||||
|
|
||||||
class C(object):
|
|
||||||
u"""Class C.
|
|
||||||
|
|
||||||
>>> print C() # 2
|
|
||||||
42
|
|
||||||
|
|
||||||
|
|
||||||
We include some (random) encoded (utf-8) text in the text surrounding
|
|
||||||
the example. It should be ignored:
|
|
||||||
|
|
||||||
ЉЊЈЁЂ
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""C.__init__.
|
|
||||||
|
|
||||||
>>> print C() # 3
|
|
||||||
42
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""
|
|
||||||
>>> print C() # 4
|
|
||||||
42
|
|
||||||
"""
|
|
||||||
return "42"
|
|
||||||
|
|
||||||
class D(object):
|
|
||||||
"""A nested D class.
|
|
||||||
|
|
||||||
>>> print "In D!" # 5
|
|
||||||
In D!
|
|
||||||
"""
|
|
||||||
|
|
||||||
def nested(self):
|
|
||||||
"""
|
|
||||||
>>> print 3 # 6
|
|
||||||
3
|
|
||||||
"""
|
|
||||||
|
|
||||||
def getx(self):
|
|
||||||
"""
|
|
||||||
>>> c = C() # 7
|
|
||||||
>>> c.x = 12 # 8
|
|
||||||
>>> print c.x # 9
|
|
||||||
-12
|
|
||||||
"""
|
|
||||||
return -self._x
|
|
||||||
|
|
||||||
def setx(self, value):
|
|
||||||
"""
|
|
||||||
>>> c = C() # 10
|
|
||||||
>>> c.x = 12 # 11
|
|
||||||
>>> print c.x # 12
|
|
||||||
-12
|
|
||||||
"""
|
|
||||||
self._x = value
|
|
||||||
|
|
||||||
x = property(getx, setx, doc="""\
|
|
||||||
>>> c = C() # 13
|
|
||||||
>>> c.x = 12 # 14
|
|
||||||
>>> print c.x # 15
|
|
||||||
-12
|
|
||||||
""")
|
|
||||||
|
|
||||||
def statm():
|
|
||||||
"""
|
|
||||||
A static method.
|
|
||||||
|
|
||||||
>>> print C.statm() # 16
|
|
||||||
666
|
|
||||||
>>> print C().statm() # 17
|
|
||||||
666
|
|
||||||
"""
|
|
||||||
return 666
|
|
||||||
|
|
||||||
statm = staticmethod(statm)
|
|
||||||
|
|
||||||
def clsm(cls, val):
|
|
||||||
"""
|
|
||||||
A class method.
|
|
||||||
|
|
||||||
>>> print C.clsm(22) # 18
|
|
||||||
22
|
|
||||||
>>> print C().clsm(23) # 19
|
|
||||||
23
|
|
||||||
"""
|
|
||||||
return val
|
|
||||||
|
|
||||||
clsm = classmethod(clsm)
|
|
||||||
|
|
||||||
def test_main():
|
|
||||||
from py.__.compat.testing import test_doctest2
|
|
||||||
EXPECTED = 19
|
|
||||||
f, t = test_support.run_doctest(test_doctest2)
|
|
||||||
if t != EXPECTED:
|
|
||||||
raise test_support.TestFailed("expected %d tests to run, not %d" %
|
|
||||||
(EXPECTED, t))
|
|
||||||
|
|
||||||
# Pollute the namespace with a bunch of imported functions and classes,
|
|
||||||
# to make sure they don't get tested.
|
|
||||||
from py.compat.doctest import *
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
test_main()
|
|
|
@ -1,14 +0,0 @@
|
||||||
This is a sample doctest in a text file.
|
|
||||||
|
|
||||||
In this example, we'll rely on some silly setup:
|
|
||||||
|
|
||||||
>>> import test.test_doctest
|
|
||||||
>>> test.test_doctest.sillySetup
|
|
||||||
True
|
|
||||||
|
|
||||||
This test also has some (random) encoded (utf-8) unicode text:
|
|
||||||
|
|
||||||
ÐÐÐÐÐ
|
|
||||||
|
|
||||||
This doesn't cause a problem in the tect surrounding the examples, but
|
|
||||||
we include it here (in this test text file) to make sure. :)
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,563 +0,0 @@
|
||||||
import unittest
|
|
||||||
from test import test_support
|
|
||||||
from py.compat import subprocess
|
|
||||||
import sys
|
|
||||||
import signal
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
|
|
||||||
mswindows = (sys.platform == "win32")
|
|
||||||
|
|
||||||
#
|
|
||||||
# Depends on the following external programs: Python
|
|
||||||
#
|
|
||||||
|
|
||||||
if mswindows:
|
|
||||||
SETBINARY = ('import msvcrt; msvcrt.setmode(sys.stdout.fileno(), '
|
|
||||||
'os.O_BINARY);')
|
|
||||||
else:
|
|
||||||
SETBINARY = ''
|
|
||||||
|
|
||||||
# In a debug build, stuff like "[6580 refs]" is printed to stderr at
|
|
||||||
# shutdown time. That frustrates tests trying to check stderr produced
|
|
||||||
# from a spawned Python process.
|
|
||||||
def remove_stderr_debug_decorations(stderr):
|
|
||||||
return re.sub(r"\[\d+ refs\]\r?\n?$", "", stderr)
|
|
||||||
|
|
||||||
class ProcessTestCase(unittest.TestCase):
|
|
||||||
def mkstemp(self):
|
|
||||||
"""wrapper for mkstemp, calling mktemp if mkstemp is not available"""
|
|
||||||
if hasattr(tempfile, "mkstemp"):
|
|
||||||
return tempfile.mkstemp()
|
|
||||||
else:
|
|
||||||
fname = tempfile.mktemp()
|
|
||||||
return os.open(fname, os.O_RDWR|os.O_CREAT), fname
|
|
||||||
|
|
||||||
#
|
|
||||||
# Generic tests
|
|
||||||
#
|
|
||||||
def test_call_seq(self):
|
|
||||||
# call() function with sequence argument
|
|
||||||
rc = subprocess.call([sys.executable, "-c",
|
|
||||||
"import sys; sys.exit(47)"])
|
|
||||||
self.assertEqual(rc, 47)
|
|
||||||
|
|
||||||
def test_call_kwargs(self):
|
|
||||||
# call() function with keyword args
|
|
||||||
newenv = os.environ.copy()
|
|
||||||
newenv["FRUIT"] = "banana"
|
|
||||||
rc = subprocess.call([sys.executable, "-c",
|
|
||||||
'import sys, os;' \
|
|
||||||
'sys.exit(os.getenv("FRUIT")=="banana")'],
|
|
||||||
env=newenv)
|
|
||||||
self.assertEqual(rc, 1)
|
|
||||||
|
|
||||||
def test_stdin_none(self):
|
|
||||||
# .stdin is None when not redirected
|
|
||||||
p = subprocess.Popen([sys.executable, "-c", 'print "banana"'],
|
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.stdin, None)
|
|
||||||
|
|
||||||
def test_stdout_none(self):
|
|
||||||
# .stdout is None when not redirected
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'print " this bit of output is from a '
|
|
||||||
'test of stdout in a different '
|
|
||||||
'process ..."'],
|
|
||||||
stdin=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.stdout, None)
|
|
||||||
|
|
||||||
def test_stderr_none(self):
|
|
||||||
# .stderr is None when not redirected
|
|
||||||
p = subprocess.Popen([sys.executable, "-c", 'print "banana"'],
|
|
||||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.stderr, None)
|
|
||||||
|
|
||||||
def test_executable(self):
|
|
||||||
p = subprocess.Popen(["somethingyoudonthave",
|
|
||||||
"-c", "import sys; sys.exit(47)"],
|
|
||||||
executable=sys.executable)
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.returncode, 47)
|
|
||||||
|
|
||||||
def test_stdin_pipe(self):
|
|
||||||
# stdin redirection
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.exit(sys.stdin.read() == "pear")'],
|
|
||||||
stdin=subprocess.PIPE)
|
|
||||||
p.stdin.write("pear")
|
|
||||||
p.stdin.close()
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.returncode, 1)
|
|
||||||
|
|
||||||
def test_stdin_filedes(self):
|
|
||||||
# stdin is set to open file descriptor
|
|
||||||
tf = tempfile.TemporaryFile()
|
|
||||||
d = tf.fileno()
|
|
||||||
os.write(d, "pear")
|
|
||||||
os.lseek(d, 0, 0)
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.exit(sys.stdin.read() == "pear")'],
|
|
||||||
stdin=d)
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.returncode, 1)
|
|
||||||
|
|
||||||
def test_stdin_fileobj(self):
|
|
||||||
# stdin is set to open file object
|
|
||||||
tf = tempfile.TemporaryFile()
|
|
||||||
tf.write("pear")
|
|
||||||
tf.seek(0)
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.exit(sys.stdin.read() == "pear")'],
|
|
||||||
stdin=tf)
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(p.returncode, 1)
|
|
||||||
|
|
||||||
def test_stdout_pipe(self):
|
|
||||||
# stdout redirection
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.stdout.write("orange")'],
|
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
self.assertEqual(p.stdout.read(), "orange")
|
|
||||||
|
|
||||||
def test_stdout_filedes(self):
|
|
||||||
# stdout is set to open file descriptor
|
|
||||||
tf = tempfile.TemporaryFile()
|
|
||||||
d = tf.fileno()
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.stdout.write("orange")'],
|
|
||||||
stdout=d)
|
|
||||||
p.wait()
|
|
||||||
os.lseek(d, 0, 0)
|
|
||||||
self.assertEqual(os.read(d, 1024), "orange")
|
|
||||||
|
|
||||||
def test_stdout_fileobj(self):
|
|
||||||
# stdout is set to open file object
|
|
||||||
tf = tempfile.TemporaryFile()
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.stdout.write("orange")'],
|
|
||||||
stdout=tf)
|
|
||||||
p.wait()
|
|
||||||
tf.seek(0)
|
|
||||||
self.assertEqual(tf.read(), "orange")
|
|
||||||
|
|
||||||
def test_stderr_pipe(self):
|
|
||||||
# stderr redirection
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.stderr.write("strawberry")'],
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
self.assertEqual(remove_stderr_debug_decorations(p.stderr.read()),
|
|
||||||
"strawberry")
|
|
||||||
|
|
||||||
def test_stderr_filedes(self):
|
|
||||||
# stderr is set to open file descriptor
|
|
||||||
tf = tempfile.TemporaryFile()
|
|
||||||
d = tf.fileno()
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.stderr.write("strawberry")'],
|
|
||||||
stderr=d)
|
|
||||||
p.wait()
|
|
||||||
os.lseek(d, 0, 0)
|
|
||||||
self.assertEqual(remove_stderr_debug_decorations(os.read(d, 1024)),
|
|
||||||
"strawberry")
|
|
||||||
|
|
||||||
def test_stderr_fileobj(self):
|
|
||||||
# stderr is set to open file object
|
|
||||||
tf = tempfile.TemporaryFile()
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys; sys.stderr.write("strawberry")'],
|
|
||||||
stderr=tf)
|
|
||||||
p.wait()
|
|
||||||
tf.seek(0)
|
|
||||||
self.assertEqual(remove_stderr_debug_decorations(tf.read()),
|
|
||||||
"strawberry")
|
|
||||||
|
|
||||||
def test_stdout_stderr_pipe(self):
|
|
||||||
# capture stdout and stderr to the same pipe
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys;' \
|
|
||||||
'sys.stdout.write("apple");' \
|
|
||||||
'sys.stdout.flush();' \
|
|
||||||
'sys.stderr.write("orange")'],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT)
|
|
||||||
output = p.stdout.read()
|
|
||||||
stripped = remove_stderr_debug_decorations(output)
|
|
||||||
self.assertEqual(stripped, "appleorange")
|
|
||||||
|
|
||||||
def test_stdout_stderr_file(self):
|
|
||||||
# capture stdout and stderr to the same open file
|
|
||||||
tf = tempfile.TemporaryFile()
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys;' \
|
|
||||||
'sys.stdout.write("apple");' \
|
|
||||||
'sys.stdout.flush();' \
|
|
||||||
'sys.stderr.write("orange")'],
|
|
||||||
stdout=tf,
|
|
||||||
stderr=tf)
|
|
||||||
p.wait()
|
|
||||||
tf.seek(0)
|
|
||||||
output = tf.read()
|
|
||||||
stripped = remove_stderr_debug_decorations(output)
|
|
||||||
self.assertEqual(stripped, "appleorange")
|
|
||||||
|
|
||||||
def test_cwd(self):
|
|
||||||
tmpdir = os.getenv("TEMP", "/tmp")
|
|
||||||
# We cannot use os.path.realpath to canonicalize the path,
|
|
||||||
# since it doesn't expand Tru64 {memb} strings. See bug 1063571.
|
|
||||||
cwd = os.getcwd()
|
|
||||||
os.chdir(tmpdir)
|
|
||||||
tmpdir = os.getcwd()
|
|
||||||
os.chdir(cwd)
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;' \
|
|
||||||
'sys.stdout.write(os.getcwd())'],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
cwd=tmpdir)
|
|
||||||
normcase = os.path.normcase
|
|
||||||
self.assertEqual(normcase(p.stdout.read()), normcase(tmpdir))
|
|
||||||
|
|
||||||
def test_env(self):
|
|
||||||
newenv = os.environ.copy()
|
|
||||||
newenv["FRUIT"] = "orange"
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;' \
|
|
||||||
'sys.stdout.write(os.getenv("FRUIT"))'],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
env=newenv)
|
|
||||||
self.assertEqual(p.stdout.read(), "orange")
|
|
||||||
|
|
||||||
def test_communicate(self):
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;' \
|
|
||||||
'sys.stderr.write("pineapple");' \
|
|
||||||
'sys.stdout.write(sys.stdin.read())'],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
(stdout, stderr) = p.communicate("banana")
|
|
||||||
self.assertEqual(stdout, "banana")
|
|
||||||
self.assertEqual(remove_stderr_debug_decorations(stderr),
|
|
||||||
"pineapple")
|
|
||||||
|
|
||||||
def test_communicate_returns(self):
|
|
||||||
# communicate() should return None if no redirection is active
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
"import sys; sys.exit(47)"])
|
|
||||||
(stdout, stderr) = p.communicate()
|
|
||||||
self.assertEqual(stdout, None)
|
|
||||||
self.assertEqual(stderr, None)
|
|
||||||
|
|
||||||
def test_communicate_pipe_buf(self):
|
|
||||||
# communicate() with writes larger than pipe_buf
|
|
||||||
# This test will probably deadlock rather than fail, if
|
|
||||||
# communicate() does not work properly.
|
|
||||||
x, y = os.pipe()
|
|
||||||
if mswindows:
|
|
||||||
pipe_buf = 512
|
|
||||||
else:
|
|
||||||
pipe_buf = os.fpathconf(x, "PC_PIPE_BUF")
|
|
||||||
os.close(x)
|
|
||||||
os.close(y)
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;'
|
|
||||||
'sys.stdout.write(sys.stdin.read(47));' \
|
|
||||||
'sys.stderr.write("xyz"*%d);' \
|
|
||||||
'sys.stdout.write(sys.stdin.read())' % pipe_buf],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
string_to_write = "abc"*pipe_buf
|
|
||||||
(stdout, stderr) = p.communicate(string_to_write)
|
|
||||||
self.assertEqual(stdout, string_to_write)
|
|
||||||
|
|
||||||
def test_writes_before_communicate(self):
|
|
||||||
# stdin.write before communicate()
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;' \
|
|
||||||
'sys.stdout.write(sys.stdin.read())'],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
p.stdin.write("banana")
|
|
||||||
(stdout, stderr) = p.communicate("split")
|
|
||||||
self.assertEqual(stdout, "bananasplit")
|
|
||||||
self.assertEqual(remove_stderr_debug_decorations(stderr), "")
|
|
||||||
|
|
||||||
def test_universal_newlines(self):
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;' + SETBINARY +
|
|
||||||
'sys.stdout.write("line1\\n");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("line2\\r");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("line3\\r\\n");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("line4\\r");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("\\nline5");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("\\nline6");'],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
universal_newlines=1)
|
|
||||||
stdout = p.stdout.read()
|
|
||||||
if hasattr(open, 'newlines'):
|
|
||||||
# Interpreter with universal newline support
|
|
||||||
self.assertEqual(stdout,
|
|
||||||
"line1\nline2\nline3\nline4\nline5\nline6")
|
|
||||||
else:
|
|
||||||
# Interpreter without universal newline support
|
|
||||||
self.assertEqual(stdout,
|
|
||||||
"line1\nline2\rline3\r\nline4\r\nline5\nline6")
|
|
||||||
|
|
||||||
def test_universal_newlines_communicate(self):
|
|
||||||
# universal newlines through communicate()
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;' + SETBINARY +
|
|
||||||
'sys.stdout.write("line1\\n");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("line2\\r");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("line3\\r\\n");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("line4\\r");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("\\nline5");'
|
|
||||||
'sys.stdout.flush();'
|
|
||||||
'sys.stdout.write("\\nline6");'],
|
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
||||||
universal_newlines=1)
|
|
||||||
(stdout, stderr) = p.communicate()
|
|
||||||
if hasattr(open, 'newlines'):
|
|
||||||
# Interpreter with universal newline support
|
|
||||||
self.assertEqual(stdout,
|
|
||||||
"line1\nline2\nline3\nline4\nline5\nline6")
|
|
||||||
else:
|
|
||||||
# Interpreter without universal newline support
|
|
||||||
self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6")
|
|
||||||
|
|
||||||
def test_no_leaking(self):
|
|
||||||
# Make sure we leak no resources
|
|
||||||
if test_support.is_resource_enabled("subprocess") and not mswindows:
|
|
||||||
max_handles = 1026 # too much for most UNIX systems
|
|
||||||
else:
|
|
||||||
max_handles = 65
|
|
||||||
for i in range(max_handles):
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
"import sys;sys.stdout.write(sys.stdin.read())"],
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
data = p.communicate("lime")[0]
|
|
||||||
self.assertEqual(data, "lime")
|
|
||||||
|
|
||||||
|
|
||||||
def test_list2cmdline(self):
|
|
||||||
self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']),
|
|
||||||
'"a b c" d e')
|
|
||||||
self.assertEqual(subprocess.list2cmdline(['ab"c', '\\', 'd']),
|
|
||||||
'ab\\"c \\ d')
|
|
||||||
self.assertEqual(subprocess.list2cmdline(['a\\\\\\b', 'de fg', 'h']),
|
|
||||||
'a\\\\\\b "de fg" h')
|
|
||||||
self.assertEqual(subprocess.list2cmdline(['a\\"b', 'c', 'd']),
|
|
||||||
'a\\\\\\"b c d')
|
|
||||||
self.assertEqual(subprocess.list2cmdline(['a\\\\b c', 'd', 'e']),
|
|
||||||
'"a\\\\b c" d e')
|
|
||||||
self.assertEqual(subprocess.list2cmdline(['a\\\\b\\ c', 'd', 'e']),
|
|
||||||
'"a\\\\b\\ c" d e')
|
|
||||||
|
|
||||||
|
|
||||||
def test_poll(self):
|
|
||||||
p = subprocess.Popen([sys.executable,
|
|
||||||
"-c", "import time; time.sleep(1)"])
|
|
||||||
count = 0
|
|
||||||
while p.poll() is None:
|
|
||||||
time.sleep(0.1)
|
|
||||||
count += 1
|
|
||||||
# We expect that the poll loop probably went around about 10 times,
|
|
||||||
# but, based on system scheduling we can't control, it's possible
|
|
||||||
# poll() never returned None. It "should be" very rare that it
|
|
||||||
# didn't go around at least twice.
|
|
||||||
self.assert_(count >= 2)
|
|
||||||
# Subsequent invocations should just return the returncode
|
|
||||||
self.assertEqual(p.poll(), 0)
|
|
||||||
|
|
||||||
|
|
||||||
def test_wait(self):
|
|
||||||
p = subprocess.Popen([sys.executable,
|
|
||||||
"-c", "import time; time.sleep(2)"])
|
|
||||||
self.assertEqual(p.wait(), 0)
|
|
||||||
# Subsequent invocations should just return the returncode
|
|
||||||
self.assertEqual(p.wait(), 0)
|
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_bufsize(self):
|
|
||||||
# an invalid type of the bufsize argument should raise
|
|
||||||
# TypeError.
|
|
||||||
try:
|
|
||||||
subprocess.Popen([sys.executable, "-c", "pass"], "orange")
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.fail("Expected TypeError")
|
|
||||||
|
|
||||||
#
|
|
||||||
# POSIX tests
|
|
||||||
#
|
|
||||||
if not mswindows:
|
|
||||||
def test_exceptions(self):
|
|
||||||
# catched & re-raised exceptions
|
|
||||||
try:
|
|
||||||
p = subprocess.Popen([sys.executable, "-c", ""],
|
|
||||||
cwd="/this/path/does/not/exist")
|
|
||||||
except OSError, e:
|
|
||||||
# The attribute child_traceback should contain "os.chdir"
|
|
||||||
# somewhere.
|
|
||||||
self.assertNotEqual(e.child_traceback.find("os.chdir"), -1)
|
|
||||||
else:
|
|
||||||
self.fail("Expected OSError")
|
|
||||||
|
|
||||||
def test_run_abort(self):
|
|
||||||
# returncode handles signal termination
|
|
||||||
p = subprocess.Popen([sys.executable,
|
|
||||||
"-c", "import os; os.abort()"])
|
|
||||||
p.wait()
|
|
||||||
self.assertEqual(-p.returncode, signal.SIGABRT)
|
|
||||||
|
|
||||||
def test_preexec(self):
|
|
||||||
# preexec function
|
|
||||||
p = subprocess.Popen([sys.executable, "-c",
|
|
||||||
'import sys,os;' \
|
|
||||||
'sys.stdout.write(os.getenv("FRUIT"))'],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
preexec_fn=lambda: os.putenv("FRUIT", "apple"))
|
|
||||||
self.assertEqual(p.stdout.read(), "apple")
|
|
||||||
|
|
||||||
def test_args_string(self):
|
|
||||||
# args is a string
|
|
||||||
f, fname = self.mkstemp()
|
|
||||||
os.write(f, "#!/bin/sh\n")
|
|
||||||
os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" %
|
|
||||||
sys.executable)
|
|
||||||
os.close(f)
|
|
||||||
os.chmod(fname, 0700)
|
|
||||||
p = subprocess.Popen(fname)
|
|
||||||
p.wait()
|
|
||||||
os.remove(fname)
|
|
||||||
self.assertEqual(p.returncode, 47)
|
|
||||||
|
|
||||||
def test_invalid_args(self):
|
|
||||||
# invalid arguments should raise ValueError
|
|
||||||
self.assertRaises(ValueError, subprocess.call,
|
|
||||||
[sys.executable,
|
|
||||||
"-c", "import sys; sys.exit(47)"],
|
|
||||||
startupinfo=47)
|
|
||||||
self.assertRaises(ValueError, subprocess.call,
|
|
||||||
[sys.executable,
|
|
||||||
"-c", "import sys; sys.exit(47)"],
|
|
||||||
creationflags=47)
|
|
||||||
|
|
||||||
def test_shell_sequence(self):
|
|
||||||
# Run command through the shell (sequence)
|
|
||||||
newenv = os.environ.copy()
|
|
||||||
newenv["FRUIT"] = "apple"
|
|
||||||
p = subprocess.Popen(["echo $FRUIT"], shell=1,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
env=newenv)
|
|
||||||
self.assertEqual(p.stdout.read().strip(), "apple")
|
|
||||||
|
|
||||||
def test_shell_string(self):
|
|
||||||
# Run command through the shell (string)
|
|
||||||
newenv = os.environ.copy()
|
|
||||||
newenv["FRUIT"] = "apple"
|
|
||||||
p = subprocess.Popen("echo $FRUIT", shell=1,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
env=newenv)
|
|
||||||
self.assertEqual(p.stdout.read().strip(), "apple")
|
|
||||||
|
|
||||||
def test_call_string(self):
|
|
||||||
# call() function with string argument on UNIX
|
|
||||||
f, fname = self.mkstemp()
|
|
||||||
os.write(f, "#!/bin/sh\n")
|
|
||||||
os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" %
|
|
||||||
sys.executable)
|
|
||||||
os.close(f)
|
|
||||||
os.chmod(fname, 0700)
|
|
||||||
rc = subprocess.call(fname)
|
|
||||||
os.remove(fname)
|
|
||||||
self.assertEqual(rc, 47)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Windows tests
|
|
||||||
#
|
|
||||||
if mswindows:
|
|
||||||
def test_startupinfo(self):
|
|
||||||
# startupinfo argument
|
|
||||||
# We uses hardcoded constants, because we do not want to
|
|
||||||
# depend on win32all.
|
|
||||||
STARTF_USESHOWWINDOW = 1
|
|
||||||
SW_MAXIMIZE = 3
|
|
||||||
startupinfo = subprocess.STARTUPINFO()
|
|
||||||
startupinfo.dwFlags = STARTF_USESHOWWINDOW
|
|
||||||
startupinfo.wShowWindow = SW_MAXIMIZE
|
|
||||||
# Since Python is a console process, it won't be affected
|
|
||||||
# by wShowWindow, but the argument should be silently
|
|
||||||
# ignored
|
|
||||||
subprocess.call([sys.executable, "-c", "import sys; sys.exit(0)"],
|
|
||||||
startupinfo=startupinfo)
|
|
||||||
|
|
||||||
def test_creationflags(self):
|
|
||||||
# creationflags argument
|
|
||||||
CREATE_NEW_CONSOLE = 16
|
|
||||||
sys.stderr.write(" a DOS box should flash briefly ...\n")
|
|
||||||
subprocess.call(sys.executable +
|
|
||||||
' -c "import time; time.sleep(0.25)"',
|
|
||||||
creationflags=CREATE_NEW_CONSOLE)
|
|
||||||
|
|
||||||
def test_invalid_args(self):
|
|
||||||
# invalid arguments should raise ValueError
|
|
||||||
self.assertRaises(ValueError, subprocess.call,
|
|
||||||
[sys.executable,
|
|
||||||
"-c", "import sys; sys.exit(47)"],
|
|
||||||
preexec_fn=lambda: 1)
|
|
||||||
self.assertRaises(ValueError, subprocess.call,
|
|
||||||
[sys.executable,
|
|
||||||
"-c", "import sys; sys.exit(47)"],
|
|
||||||
close_fds=True)
|
|
||||||
|
|
||||||
def test_shell_sequence(self):
|
|
||||||
# Run command through the shell (sequence)
|
|
||||||
newenv = os.environ.copy()
|
|
||||||
newenv["FRUIT"] = "physalis"
|
|
||||||
p = subprocess.Popen(["set"], shell=1,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
env=newenv)
|
|
||||||
self.assertNotEqual(p.stdout.read().find("physalis"), -1)
|
|
||||||
|
|
||||||
def test_shell_string(self):
|
|
||||||
# Run command through the shell (string)
|
|
||||||
newenv = os.environ.copy()
|
|
||||||
newenv["FRUIT"] = "physalis"
|
|
||||||
p = subprocess.Popen("set", shell=1,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
env=newenv)
|
|
||||||
self.assertNotEqual(p.stdout.read().find("physalis"), -1)
|
|
||||||
|
|
||||||
def test_call_string(self):
|
|
||||||
# call() function with string argument on Windows
|
|
||||||
rc = subprocess.call(sys.executable +
|
|
||||||
' -c "import sys; sys.exit(47)"')
|
|
||||||
self.assertEqual(rc, 47)
|
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
|
||||||
test_support.run_unittest(ProcessTestCase)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
test_main()
|
|
|
@ -1,532 +0,0 @@
|
||||||
#
|
|
||||||
# Test suite for the textwrap module.
|
|
||||||
#
|
|
||||||
# Original tests written by Greg Ward <gward@python.net>.
|
|
||||||
# Converted to PyUnit by Peter Hansen <peter@engcorp.com>.
|
|
||||||
# Currently maintained by Greg Ward.
|
|
||||||
#
|
|
||||||
# $Id: test_textwrap.py 38573 2005-03-05 02:38:33Z gward $
|
|
||||||
#
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from test import test_support
|
|
||||||
|
|
||||||
import py
|
|
||||||
textwrap = py.compat.textwrap
|
|
||||||
TextWrapper = textwrap.TextWrapper
|
|
||||||
wrap = textwrap.wrap
|
|
||||||
fill = textwrap.fill
|
|
||||||
dedent = textwrap.dedent
|
|
||||||
|
|
||||||
class BaseTestCase(unittest.TestCase):
|
|
||||||
'''Parent class with utility methods for textwrap tests.'''
|
|
||||||
|
|
||||||
def show(self, textin):
|
|
||||||
if isinstance(textin, list):
|
|
||||||
result = []
|
|
||||||
for i in range(len(textin)):
|
|
||||||
result.append(" %d: %r" % (i, textin[i]))
|
|
||||||
result = '\n'.join(result)
|
|
||||||
elif isinstance(textin, basestring):
|
|
||||||
result = " %s\n" % repr(textin)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def check(self, result, expect):
|
|
||||||
self.assertEquals(result, expect,
|
|
||||||
'expected:\n%s\nbut got:\n%s' % (
|
|
||||||
self.show(expect), self.show(result)))
|
|
||||||
|
|
||||||
def check_wrap(self, text, width, expect, **kwargs):
|
|
||||||
result = wrap(text, width, **kwargs)
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
def check_split(self, text, expect):
|
|
||||||
result = self.wrapper._split(text)
|
|
||||||
self.assertEquals(result, expect,
|
|
||||||
"\nexpected %r\n"
|
|
||||||
"but got %r" % (expect, result))
|
|
||||||
|
|
||||||
|
|
||||||
class WrapTestCase(BaseTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.wrapper = TextWrapper(width=45)
|
|
||||||
|
|
||||||
def test_simple(self):
|
|
||||||
# Simple case: just words, spaces, and a bit of punctuation
|
|
||||||
|
|
||||||
text = "Hello there, how are you this fine day? I'm glad to hear it!"
|
|
||||||
|
|
||||||
self.check_wrap(text, 12,
|
|
||||||
["Hello there,",
|
|
||||||
"how are you",
|
|
||||||
"this fine",
|
|
||||||
"day? I'm",
|
|
||||||
"glad to hear",
|
|
||||||
"it!"])
|
|
||||||
self.check_wrap(text, 42,
|
|
||||||
["Hello there, how are you this fine day?",
|
|
||||||
"I'm glad to hear it!"])
|
|
||||||
self.check_wrap(text, 80, [text])
|
|
||||||
|
|
||||||
|
|
||||||
def test_whitespace(self):
|
|
||||||
# Whitespace munging and end-of-sentence detection
|
|
||||||
|
|
||||||
text = """\
|
|
||||||
This is a paragraph that already has
|
|
||||||
line breaks. But some of its lines are much longer than the others,
|
|
||||||
so it needs to be wrapped.
|
|
||||||
Some lines are \ttabbed too.
|
|
||||||
What a mess!
|
|
||||||
"""
|
|
||||||
|
|
||||||
expect = ["This is a paragraph that already has line",
|
|
||||||
"breaks. But some of its lines are much",
|
|
||||||
"longer than the others, so it needs to be",
|
|
||||||
"wrapped. Some lines are tabbed too. What a",
|
|
||||||
"mess!"]
|
|
||||||
|
|
||||||
wrapper = TextWrapper(45, fix_sentence_endings=True)
|
|
||||||
result = wrapper.wrap(text)
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
result = wrapper.fill(text)
|
|
||||||
self.check(result, '\n'.join(expect))
|
|
||||||
|
|
||||||
def test_fix_sentence_endings(self):
|
|
||||||
wrapper = TextWrapper(60, fix_sentence_endings=True)
|
|
||||||
|
|
||||||
# SF #847346: ensure that fix_sentence_endings=True does the
|
|
||||||
# right thing even on input short enough that it doesn't need to
|
|
||||||
# be wrapped.
|
|
||||||
text = "A short line. Note the single space."
|
|
||||||
expect = ["A short line. Note the single space."]
|
|
||||||
self.check(wrapper.wrap(text), expect)
|
|
||||||
|
|
||||||
# Test some of the hairy end cases that _fix_sentence_endings()
|
|
||||||
# is supposed to handle (the easy stuff is tested in
|
|
||||||
# test_whitespace() above).
|
|
||||||
text = "Well, Doctor? What do you think?"
|
|
||||||
expect = ["Well, Doctor? What do you think?"]
|
|
||||||
self.check(wrapper.wrap(text), expect)
|
|
||||||
|
|
||||||
text = "Well, Doctor?\nWhat do you think?"
|
|
||||||
self.check(wrapper.wrap(text), expect)
|
|
||||||
|
|
||||||
text = 'I say, chaps! Anyone for "tennis?"\nHmmph!'
|
|
||||||
expect = ['I say, chaps! Anyone for "tennis?" Hmmph!']
|
|
||||||
self.check(wrapper.wrap(text), expect)
|
|
||||||
|
|
||||||
wrapper.width = 20
|
|
||||||
expect = ['I say, chaps!', 'Anyone for "tennis?"', 'Hmmph!']
|
|
||||||
self.check(wrapper.wrap(text), expect)
|
|
||||||
|
|
||||||
text = 'And she said, "Go to hell!"\nCan you believe that?'
|
|
||||||
expect = ['And she said, "Go to',
|
|
||||||
'hell!" Can you',
|
|
||||||
'believe that?']
|
|
||||||
self.check(wrapper.wrap(text), expect)
|
|
||||||
|
|
||||||
wrapper.width = 60
|
|
||||||
expect = ['And she said, "Go to hell!" Can you believe that?']
|
|
||||||
self.check(wrapper.wrap(text), expect)
|
|
||||||
|
|
||||||
def test_wrap_short(self):
|
|
||||||
# Wrapping to make short lines longer
|
|
||||||
|
|
||||||
text = "This is a\nshort paragraph."
|
|
||||||
|
|
||||||
self.check_wrap(text, 20, ["This is a short",
|
|
||||||
"paragraph."])
|
|
||||||
self.check_wrap(text, 40, ["This is a short paragraph."])
|
|
||||||
|
|
||||||
|
|
||||||
def test_wrap_short_1line(self):
|
|
||||||
# Test endcases
|
|
||||||
|
|
||||||
text = "This is a short line."
|
|
||||||
|
|
||||||
self.check_wrap(text, 30, ["This is a short line."])
|
|
||||||
self.check_wrap(text, 30, ["(1) This is a short line."],
|
|
||||||
initial_indent="(1) ")
|
|
||||||
|
|
||||||
|
|
||||||
def test_hyphenated(self):
|
|
||||||
# Test breaking hyphenated words
|
|
||||||
|
|
||||||
text = ("this-is-a-useful-feature-for-"
|
|
||||||
"reformatting-posts-from-tim-peters'ly")
|
|
||||||
|
|
||||||
self.check_wrap(text, 40,
|
|
||||||
["this-is-a-useful-feature-for-",
|
|
||||||
"reformatting-posts-from-tim-peters'ly"])
|
|
||||||
self.check_wrap(text, 41,
|
|
||||||
["this-is-a-useful-feature-for-",
|
|
||||||
"reformatting-posts-from-tim-peters'ly"])
|
|
||||||
self.check_wrap(text, 42,
|
|
||||||
["this-is-a-useful-feature-for-reformatting-",
|
|
||||||
"posts-from-tim-peters'ly"])
|
|
||||||
|
|
||||||
def test_hyphenated_numbers(self):
|
|
||||||
# Test that hyphenated numbers (eg. dates) are not broken like words.
|
|
||||||
text = ("Python 1.0.0 was released on 1994-01-26. Python 1.0.1 was\n"
|
|
||||||
"released on 1994-02-15.")
|
|
||||||
|
|
||||||
self.check_wrap(text, 30, ['Python 1.0.0 was released on',
|
|
||||||
'1994-01-26. Python 1.0.1 was',
|
|
||||||
'released on 1994-02-15.'])
|
|
||||||
self.check_wrap(text, 40, ['Python 1.0.0 was released on 1994-01-26.',
|
|
||||||
'Python 1.0.1 was released on 1994-02-15.'])
|
|
||||||
|
|
||||||
text = "I do all my shopping at 7-11."
|
|
||||||
self.check_wrap(text, 25, ["I do all my shopping at",
|
|
||||||
"7-11."])
|
|
||||||
self.check_wrap(text, 27, ["I do all my shopping at",
|
|
||||||
"7-11."])
|
|
||||||
self.check_wrap(text, 29, ["I do all my shopping at 7-11."])
|
|
||||||
|
|
||||||
def test_em_dash(self):
|
|
||||||
# Test text with em-dashes
|
|
||||||
text = "Em-dashes should be written -- thus."
|
|
||||||
self.check_wrap(text, 25,
|
|
||||||
["Em-dashes should be",
|
|
||||||
"written -- thus."])
|
|
||||||
|
|
||||||
# Probe the boundaries of the properly written em-dash,
|
|
||||||
# ie. " -- ".
|
|
||||||
self.check_wrap(text, 29,
|
|
||||||
["Em-dashes should be written",
|
|
||||||
"-- thus."])
|
|
||||||
expect = ["Em-dashes should be written --",
|
|
||||||
"thus."]
|
|
||||||
self.check_wrap(text, 30, expect)
|
|
||||||
self.check_wrap(text, 35, expect)
|
|
||||||
self.check_wrap(text, 36,
|
|
||||||
["Em-dashes should be written -- thus."])
|
|
||||||
|
|
||||||
# The improperly written em-dash is handled too, because
|
|
||||||
# it's adjacent to non-whitespace on both sides.
|
|
||||||
text = "You can also do--this or even---this."
|
|
||||||
expect = ["You can also do",
|
|
||||||
"--this or even",
|
|
||||||
"---this."]
|
|
||||||
self.check_wrap(text, 15, expect)
|
|
||||||
self.check_wrap(text, 16, expect)
|
|
||||||
expect = ["You can also do--",
|
|
||||||
"this or even---",
|
|
||||||
"this."]
|
|
||||||
self.check_wrap(text, 17, expect)
|
|
||||||
self.check_wrap(text, 19, expect)
|
|
||||||
expect = ["You can also do--this or even",
|
|
||||||
"---this."]
|
|
||||||
self.check_wrap(text, 29, expect)
|
|
||||||
self.check_wrap(text, 31, expect)
|
|
||||||
expect = ["You can also do--this or even---",
|
|
||||||
"this."]
|
|
||||||
self.check_wrap(text, 32, expect)
|
|
||||||
self.check_wrap(text, 35, expect)
|
|
||||||
|
|
||||||
# All of the above behaviour could be deduced by probing the
|
|
||||||
# _split() method.
|
|
||||||
text = "Here's an -- em-dash and--here's another---and another!"
|
|
||||||
expect = ["Here's", " ", "an", " ", "--", " ", "em-", "dash", " ",
|
|
||||||
"and", "--", "here's", " ", "another", "---",
|
|
||||||
"and", " ", "another!"]
|
|
||||||
self.check_split(text, expect)
|
|
||||||
|
|
||||||
text = "and then--bam!--he was gone"
|
|
||||||
expect = ["and", " ", "then", "--", "bam!", "--",
|
|
||||||
"he", " ", "was", " ", "gone"]
|
|
||||||
self.check_split(text, expect)
|
|
||||||
|
|
||||||
|
|
||||||
def test_unix_options (self):
|
|
||||||
# Test that Unix-style command-line options are wrapped correctly.
|
|
||||||
# Both Optik (OptionParser) and Docutils rely on this behaviour!
|
|
||||||
|
|
||||||
text = "You should use the -n option, or --dry-run in its long form."
|
|
||||||
self.check_wrap(text, 20,
|
|
||||||
["You should use the",
|
|
||||||
"-n option, or --dry-",
|
|
||||||
"run in its long",
|
|
||||||
"form."])
|
|
||||||
self.check_wrap(text, 21,
|
|
||||||
["You should use the -n",
|
|
||||||
"option, or --dry-run",
|
|
||||||
"in its long form."])
|
|
||||||
expect = ["You should use the -n option, or",
|
|
||||||
"--dry-run in its long form."]
|
|
||||||
self.check_wrap(text, 32, expect)
|
|
||||||
self.check_wrap(text, 34, expect)
|
|
||||||
self.check_wrap(text, 35, expect)
|
|
||||||
self.check_wrap(text, 38, expect)
|
|
||||||
expect = ["You should use the -n option, or --dry-",
|
|
||||||
"run in its long form."]
|
|
||||||
self.check_wrap(text, 39, expect)
|
|
||||||
self.check_wrap(text, 41, expect)
|
|
||||||
expect = ["You should use the -n option, or --dry-run",
|
|
||||||
"in its long form."]
|
|
||||||
self.check_wrap(text, 42, expect)
|
|
||||||
|
|
||||||
# Again, all of the above can be deduced from _split().
|
|
||||||
text = "the -n option, or --dry-run or --dryrun"
|
|
||||||
expect = ["the", " ", "-n", " ", "option,", " ", "or", " ",
|
|
||||||
"--dry-", "run", " ", "or", " ", "--dryrun"]
|
|
||||||
self.check_split(text, expect)
|
|
||||||
|
|
||||||
def test_funky_hyphens (self):
|
|
||||||
# Screwy edge cases cooked up by David Goodger. All reported
|
|
||||||
# in SF bug #596434.
|
|
||||||
self.check_split("what the--hey!", ["what", " ", "the", "--", "hey!"])
|
|
||||||
self.check_split("what the--", ["what", " ", "the--"])
|
|
||||||
self.check_split("what the--.", ["what", " ", "the--."])
|
|
||||||
self.check_split("--text--.", ["--text--."])
|
|
||||||
|
|
||||||
# When I first read bug #596434, this is what I thought David
|
|
||||||
# was talking about. I was wrong; these have always worked
|
|
||||||
# fine. The real problem is tested in test_funky_parens()
|
|
||||||
# below...
|
|
||||||
self.check_split("--option", ["--option"])
|
|
||||||
self.check_split("--option-opt", ["--option-", "opt"])
|
|
||||||
self.check_split("foo --option-opt bar",
|
|
||||||
["foo", " ", "--option-", "opt", " ", "bar"])
|
|
||||||
|
|
||||||
def test_punct_hyphens(self):
|
|
||||||
# Oh bother, SF #965425 found another problem with hyphens --
|
|
||||||
# hyphenated words in single quotes weren't handled correctly.
|
|
||||||
# In fact, the bug is that *any* punctuation around a hyphenated
|
|
||||||
# word was handled incorrectly, except for a leading "--", which
|
|
||||||
# was special-cased for Optik and Docutils. So test a variety
|
|
||||||
# of styles of punctuation around a hyphenated word.
|
|
||||||
# (Actually this is based on an Optik bug report, #813077).
|
|
||||||
self.check_split("the 'wibble-wobble' widget",
|
|
||||||
['the', ' ', "'wibble-", "wobble'", ' ', 'widget'])
|
|
||||||
self.check_split('the "wibble-wobble" widget',
|
|
||||||
['the', ' ', '"wibble-', 'wobble"', ' ', 'widget'])
|
|
||||||
self.check_split("the (wibble-wobble) widget",
|
|
||||||
['the', ' ', "(wibble-", "wobble)", ' ', 'widget'])
|
|
||||||
self.check_split("the ['wibble-wobble'] widget",
|
|
||||||
['the', ' ', "['wibble-", "wobble']", ' ', 'widget'])
|
|
||||||
|
|
||||||
def test_funky_parens (self):
|
|
||||||
# Second part of SF bug #596434: long option strings inside
|
|
||||||
# parentheses.
|
|
||||||
self.check_split("foo (--option) bar",
|
|
||||||
["foo", " ", "(--option)", " ", "bar"])
|
|
||||||
|
|
||||||
# Related stuff -- make sure parens work in simpler contexts.
|
|
||||||
self.check_split("foo (bar) baz",
|
|
||||||
["foo", " ", "(bar)", " ", "baz"])
|
|
||||||
self.check_split("blah (ding dong), wubba",
|
|
||||||
["blah", " ", "(ding", " ", "dong),",
|
|
||||||
" ", "wubba"])
|
|
||||||
|
|
||||||
def test_initial_whitespace(self):
|
|
||||||
# SF bug #622849 reported inconsistent handling of leading
|
|
||||||
# whitespace; let's test that a bit, shall we?
|
|
||||||
text = " This is a sentence with leading whitespace."
|
|
||||||
self.check_wrap(text, 50,
|
|
||||||
[" This is a sentence with leading whitespace."])
|
|
||||||
self.check_wrap(text, 30,
|
|
||||||
[" This is a sentence with", "leading whitespace."])
|
|
||||||
|
|
||||||
def test_unicode(self):
|
|
||||||
# *Very* simple test of wrapping Unicode strings. I'm sure
|
|
||||||
# there's more to it than this, but let's at least make
|
|
||||||
# sure textwrap doesn't crash on Unicode input!
|
|
||||||
text = u"Hello there, how are you today?"
|
|
||||||
self.check_wrap(text, 50, [u"Hello there, how are you today?"])
|
|
||||||
self.check_wrap(text, 20, [u"Hello there, how are", "you today?"])
|
|
||||||
olines = self.wrapper.wrap(text)
|
|
||||||
assert isinstance(olines, list) and isinstance(olines[0], unicode)
|
|
||||||
otext = self.wrapper.fill(text)
|
|
||||||
assert isinstance(otext, unicode)
|
|
||||||
|
|
||||||
def test_split(self):
|
|
||||||
# Ensure that the standard _split() method works as advertised
|
|
||||||
# in the comments
|
|
||||||
|
|
||||||
text = "Hello there -- you goof-ball, use the -b option!"
|
|
||||||
|
|
||||||
result = self.wrapper._split(text)
|
|
||||||
self.check(result,
|
|
||||||
["Hello", " ", "there", " ", "--", " ", "you", " ", "goof-",
|
|
||||||
"ball,", " ", "use", " ", "the", " ", "-b", " ", "option!"])
|
|
||||||
|
|
||||||
def test_bad_width(self):
|
|
||||||
# Ensure that width <= 0 is caught.
|
|
||||||
text = "Whatever, it doesn't matter."
|
|
||||||
self.assertRaises(ValueError, wrap, text, 0)
|
|
||||||
self.assertRaises(ValueError, wrap, text, -1)
|
|
||||||
|
|
||||||
|
|
||||||
class LongWordTestCase (BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.wrapper = TextWrapper()
|
|
||||||
self.text = '''\
|
|
||||||
Did you say "supercalifragilisticexpialidocious?"
|
|
||||||
How *do* you spell that odd word, anyways?
|
|
||||||
'''
|
|
||||||
|
|
||||||
def test_break_long(self):
|
|
||||||
# Wrap text with long words and lots of punctuation
|
|
||||||
|
|
||||||
self.check_wrap(self.text, 30,
|
|
||||||
['Did you say "supercalifragilis',
|
|
||||||
'ticexpialidocious?" How *do*',
|
|
||||||
'you spell that odd word,',
|
|
||||||
'anyways?'])
|
|
||||||
self.check_wrap(self.text, 50,
|
|
||||||
['Did you say "supercalifragilisticexpialidocious?"',
|
|
||||||
'How *do* you spell that odd word, anyways?'])
|
|
||||||
|
|
||||||
# SF bug 797650. Prevent an infinite loop by making sure that at
|
|
||||||
# least one character gets split off on every pass.
|
|
||||||
self.check_wrap('-'*10+'hello', 10,
|
|
||||||
['----------',
|
|
||||||
' h',
|
|
||||||
' e',
|
|
||||||
' l',
|
|
||||||
' l',
|
|
||||||
' o'],
|
|
||||||
subsequent_indent = ' '*15)
|
|
||||||
|
|
||||||
def test_nobreak_long(self):
|
|
||||||
# Test with break_long_words disabled
|
|
||||||
self.wrapper.break_long_words = 0
|
|
||||||
self.wrapper.width = 30
|
|
||||||
expect = ['Did you say',
|
|
||||||
'"supercalifragilisticexpialidocious?"',
|
|
||||||
'How *do* you spell that odd',
|
|
||||||
'word, anyways?'
|
|
||||||
]
|
|
||||||
result = self.wrapper.wrap(self.text)
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
# Same thing with kwargs passed to standalone wrap() function.
|
|
||||||
result = wrap(self.text, width=30, break_long_words=0)
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
|
|
||||||
class IndentTestCases(BaseTestCase):
|
|
||||||
|
|
||||||
# called before each test method
|
|
||||||
def setUp(self):
|
|
||||||
self.text = '''\
|
|
||||||
This paragraph will be filled, first without any indentation,
|
|
||||||
and then with some (including a hanging indent).'''
|
|
||||||
|
|
||||||
|
|
||||||
def test_fill(self):
|
|
||||||
# Test the fill() method
|
|
||||||
|
|
||||||
expect = '''\
|
|
||||||
This paragraph will be filled, first
|
|
||||||
without any indentation, and then with
|
|
||||||
some (including a hanging indent).'''
|
|
||||||
|
|
||||||
result = fill(self.text, 40)
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
|
|
||||||
def test_initial_indent(self):
|
|
||||||
# Test initial_indent parameter
|
|
||||||
|
|
||||||
expect = [" This paragraph will be filled,",
|
|
||||||
"first without any indentation, and then",
|
|
||||||
"with some (including a hanging indent)."]
|
|
||||||
result = wrap(self.text, 40, initial_indent=" ")
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
expect = "\n".join(expect)
|
|
||||||
result = fill(self.text, 40, initial_indent=" ")
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
|
|
||||||
def test_subsequent_indent(self):
|
|
||||||
# Test subsequent_indent parameter
|
|
||||||
|
|
||||||
expect = '''\
|
|
||||||
* This paragraph will be filled, first
|
|
||||||
without any indentation, and then
|
|
||||||
with some (including a hanging
|
|
||||||
indent).'''
|
|
||||||
|
|
||||||
result = fill(self.text, 40,
|
|
||||||
initial_indent=" * ", subsequent_indent=" ")
|
|
||||||
self.check(result, expect)
|
|
||||||
|
|
||||||
|
|
||||||
# Despite the similar names, DedentTestCase is *not* the inverse
|
|
||||||
# of IndentTestCase!
|
|
||||||
class DedentTestCase(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_dedent_nomargin(self):
|
|
||||||
# No lines indented.
|
|
||||||
text = "Hello there.\nHow are you?\nOh good, I'm glad."
|
|
||||||
self.assertEquals(dedent(text), text)
|
|
||||||
|
|
||||||
# Similar, with a blank line.
|
|
||||||
text = "Hello there.\n\nBoo!"
|
|
||||||
self.assertEquals(dedent(text), text)
|
|
||||||
|
|
||||||
# Some lines indented, but overall margin is still zero.
|
|
||||||
text = "Hello there.\n This is indented."
|
|
||||||
self.assertEquals(dedent(text), text)
|
|
||||||
|
|
||||||
# Again, add a blank line.
|
|
||||||
text = "Hello there.\n\n Boo!\n"
|
|
||||||
self.assertEquals(dedent(text), text)
|
|
||||||
|
|
||||||
def test_dedent_even(self):
|
|
||||||
# All lines indented by two spaces.
|
|
||||||
text = " Hello there.\n How are ya?\n Oh good."
|
|
||||||
expect = "Hello there.\nHow are ya?\nOh good."
|
|
||||||
self.assertEquals(dedent(text), expect)
|
|
||||||
|
|
||||||
# Same, with blank lines.
|
|
||||||
text = " Hello there.\n\n How are ya?\n Oh good.\n"
|
|
||||||
expect = "Hello there.\n\nHow are ya?\nOh good.\n"
|
|
||||||
self.assertEquals(dedent(text), expect)
|
|
||||||
|
|
||||||
# Now indent one of the blank lines.
|
|
||||||
text = " Hello there.\n \n How are ya?\n Oh good.\n"
|
|
||||||
expect = "Hello there.\n\nHow are ya?\nOh good.\n"
|
|
||||||
self.assertEquals(dedent(text), expect)
|
|
||||||
|
|
||||||
def test_dedent_uneven(self):
|
|
||||||
# Lines indented unevenly.
|
|
||||||
text = '''\
|
|
||||||
def foo():
|
|
||||||
while 1:
|
|
||||||
return foo
|
|
||||||
'''
|
|
||||||
expect = '''\
|
|
||||||
def foo():
|
|
||||||
while 1:
|
|
||||||
return foo
|
|
||||||
'''
|
|
||||||
self.assertEquals(dedent(text), expect)
|
|
||||||
|
|
||||||
# Uneven indentation with a blank line.
|
|
||||||
text = " Foo\n Bar\n\n Baz\n"
|
|
||||||
expect = "Foo\n Bar\n\n Baz\n"
|
|
||||||
self.assertEquals(dedent(text), expect)
|
|
||||||
|
|
||||||
# Uneven indentation with a whitespace-only line.
|
|
||||||
text = " Foo\n Bar\n \n Baz\n"
|
|
||||||
expect = "Foo\n Bar\n\n Baz\n"
|
|
||||||
self.assertEquals(dedent(text), expect)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
|
||||||
test_support.run_unittest(WrapTestCase,
|
|
||||||
LongWordTestCase,
|
|
||||||
IndentTestCases,
|
|
||||||
DedentTestCase)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
test_main()
|
|
|
@ -1,357 +0,0 @@
|
||||||
"""Text wrapping and filling.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (C) 1999-2001 Gregory P. Ward.
|
|
||||||
# Copyright (C) 2002, 2003 Python Software Foundation.
|
|
||||||
# Written by Greg Ward <gward@python.net>
|
|
||||||
|
|
||||||
__revision__ = "$Id: textwrap.py 36379 2007-01-09 16:55:49Z cfbolz $"
|
|
||||||
|
|
||||||
import string, re
|
|
||||||
|
|
||||||
# Do the right thing with boolean values for all known Python versions
|
|
||||||
# (so this module can be copied to projects that don't depend on Python
|
|
||||||
# 2.3, e.g. Optik and Docutils).
|
|
||||||
try:
|
|
||||||
True, False
|
|
||||||
except NameError:
|
|
||||||
(True, False) = (1, 0)
|
|
||||||
|
|
||||||
__all__ = ['TextWrapper', 'wrap', 'fill']
|
|
||||||
|
|
||||||
# Hardcode the recognized whitespace characters to the US-ASCII
|
|
||||||
# whitespace characters. The main reason for doing this is that in
|
|
||||||
# ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales
|
|
||||||
# that character winds up in string.whitespace. Respecting
|
|
||||||
# string.whitespace in those cases would 1) make textwrap treat 0xa0 the
|
|
||||||
# same as any other whitespace char, which is clearly wrong (it's a
|
|
||||||
# *non-breaking* space), 2) possibly cause problems with Unicode,
|
|
||||||
# since 0xa0 is not in range(128).
|
|
||||||
_whitespace = '\t\n\x0b\x0c\r '
|
|
||||||
|
|
||||||
class TextWrapper:
|
|
||||||
"""
|
|
||||||
Object for wrapping/filling text. The public interface consists of
|
|
||||||
the wrap() and fill() methods; the other methods are just there for
|
|
||||||
subclasses to override in order to tweak the default behaviour.
|
|
||||||
If you want to completely replace the main wrapping algorithm,
|
|
||||||
you'll probably have to override _wrap_chunks().
|
|
||||||
|
|
||||||
Several instance attributes control various aspects of wrapping:
|
|
||||||
width (default: 70)
|
|
||||||
the maximum width of wrapped lines (unless break_long_words
|
|
||||||
is false)
|
|
||||||
initial_indent (default: "")
|
|
||||||
string that will be prepended to the first line of wrapped
|
|
||||||
output. Counts towards the line's width.
|
|
||||||
subsequent_indent (default: "")
|
|
||||||
string that will be prepended to all lines save the first
|
|
||||||
of wrapped output; also counts towards each line's width.
|
|
||||||
expand_tabs (default: true)
|
|
||||||
Expand tabs in input text to spaces before further processing.
|
|
||||||
Each tab will become 1 .. 8 spaces, depending on its position in
|
|
||||||
its line. If false, each tab is treated as a single character.
|
|
||||||
replace_whitespace (default: true)
|
|
||||||
Replace all whitespace characters in the input text by spaces
|
|
||||||
after tab expansion. Note that if expand_tabs is false and
|
|
||||||
replace_whitespace is true, every tab will be converted to a
|
|
||||||
single space!
|
|
||||||
fix_sentence_endings (default: false)
|
|
||||||
Ensure that sentence-ending punctuation is always followed
|
|
||||||
by two spaces. Off by default because the algorithm is
|
|
||||||
(unavoidably) imperfect.
|
|
||||||
break_long_words (default: true)
|
|
||||||
Break words longer than 'width'. If false, those words will not
|
|
||||||
be broken, and some lines might be longer than 'width'.
|
|
||||||
"""
|
|
||||||
|
|
||||||
whitespace_trans = string.maketrans(_whitespace, ' ' * len(_whitespace))
|
|
||||||
|
|
||||||
unicode_whitespace_trans = {}
|
|
||||||
uspace = ord(u' ')
|
|
||||||
for x in map(ord, _whitespace):
|
|
||||||
unicode_whitespace_trans[x] = uspace
|
|
||||||
|
|
||||||
# This funky little regex is just the trick for splitting
|
|
||||||
# text up into word-wrappable chunks. E.g.
|
|
||||||
# "Hello there -- you goof-ball, use the -b option!"
|
|
||||||
# splits into
|
|
||||||
# Hello/ /there/ /--/ /you/ /goof-/ball,/ /use/ /the/ /-b/ /option!
|
|
||||||
# (after stripping out empty strings).
|
|
||||||
wordsep_re = re.compile(
|
|
||||||
r'(\s+|' # any whitespace
|
|
||||||
r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words
|
|
||||||
r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash
|
|
||||||
|
|
||||||
# XXX this is not locale- or charset-aware -- string.lowercase
|
|
||||||
# is US-ASCII only (and therefore English-only)
|
|
||||||
sentence_end_re = re.compile(r'[%s]' # lowercase letter
|
|
||||||
r'[\.\!\?]' # sentence-ending punct.
|
|
||||||
r'[\"\']?' # optional end-of-quote
|
|
||||||
% string.lowercase)
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
width=70,
|
|
||||||
initial_indent="",
|
|
||||||
subsequent_indent="",
|
|
||||||
expand_tabs=True,
|
|
||||||
replace_whitespace=True,
|
|
||||||
fix_sentence_endings=False,
|
|
||||||
break_long_words=True):
|
|
||||||
self.width = width
|
|
||||||
self.initial_indent = initial_indent
|
|
||||||
self.subsequent_indent = subsequent_indent
|
|
||||||
self.expand_tabs = expand_tabs
|
|
||||||
self.replace_whitespace = replace_whitespace
|
|
||||||
self.fix_sentence_endings = fix_sentence_endings
|
|
||||||
self.break_long_words = break_long_words
|
|
||||||
|
|
||||||
|
|
||||||
# -- Private methods -----------------------------------------------
|
|
||||||
# (possibly useful for subclasses to override)
|
|
||||||
|
|
||||||
def _munge_whitespace(self, text):
|
|
||||||
"""_munge_whitespace(text : string) -> string
|
|
||||||
|
|
||||||
Munge whitespace in text: expand tabs and convert all other
|
|
||||||
whitespace characters to spaces. Eg. " foo\tbar\n\nbaz"
|
|
||||||
becomes " foo bar baz".
|
|
||||||
"""
|
|
||||||
if self.expand_tabs:
|
|
||||||
text = text.expandtabs()
|
|
||||||
if self.replace_whitespace:
|
|
||||||
if isinstance(text, str):
|
|
||||||
text = text.translate(self.whitespace_trans)
|
|
||||||
elif isinstance(text, unicode):
|
|
||||||
text = text.translate(self.unicode_whitespace_trans)
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
def _split(self, text):
|
|
||||||
"""_split(text : string) -> [string]
|
|
||||||
|
|
||||||
Split the text to wrap into indivisible chunks. Chunks are
|
|
||||||
not quite the same as words; see wrap_chunks() for full
|
|
||||||
details. As an example, the text
|
|
||||||
Look, goof-ball -- use the -b option!
|
|
||||||
breaks into the following chunks:
|
|
||||||
'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ',
|
|
||||||
'use', ' ', 'the', ' ', '-b', ' ', 'option!'
|
|
||||||
"""
|
|
||||||
chunks = self.wordsep_re.split(text)
|
|
||||||
chunks = filter(None, chunks)
|
|
||||||
return chunks
|
|
||||||
|
|
||||||
def _fix_sentence_endings(self, chunks):
|
|
||||||
"""_fix_sentence_endings(chunks : [string])
|
|
||||||
|
|
||||||
Correct for sentence endings buried in 'chunks'. Eg. when the
|
|
||||||
original text contains "... foo.\nBar ...", munge_whitespace()
|
|
||||||
and split() will convert that to [..., "foo.", " ", "Bar", ...]
|
|
||||||
which has one too few spaces; this method simply changes the one
|
|
||||||
space to two.
|
|
||||||
"""
|
|
||||||
i = 0
|
|
||||||
pat = self.sentence_end_re
|
|
||||||
while i < len(chunks)-1:
|
|
||||||
if chunks[i+1] == " " and pat.search(chunks[i]):
|
|
||||||
chunks[i+1] = " "
|
|
||||||
i += 2
|
|
||||||
else:
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
|
|
||||||
"""_handle_long_word(chunks : [string],
|
|
||||||
cur_line : [string],
|
|
||||||
cur_len : int, width : int)
|
|
||||||
|
|
||||||
Handle a chunk of text (most likely a word, not whitespace) that
|
|
||||||
is too long to fit in any line.
|
|
||||||
"""
|
|
||||||
space_left = max(width - cur_len, 1)
|
|
||||||
|
|
||||||
# If we're allowed to break long words, then do so: put as much
|
|
||||||
# of the next chunk onto the current line as will fit.
|
|
||||||
if self.break_long_words:
|
|
||||||
cur_line.append(reversed_chunks[-1][:space_left])
|
|
||||||
reversed_chunks[-1] = reversed_chunks[-1][space_left:]
|
|
||||||
|
|
||||||
# Otherwise, we have to preserve the long word intact. Only add
|
|
||||||
# it to the current line if there's nothing already there --
|
|
||||||
# that minimizes how much we violate the width constraint.
|
|
||||||
elif not cur_line:
|
|
||||||
cur_line.append(reversed_chunks.pop())
|
|
||||||
|
|
||||||
# If we're not allowed to break long words, and there's already
|
|
||||||
# text on the current line, do nothing. Next time through the
|
|
||||||
# main loop of _wrap_chunks(), we'll wind up here again, but
|
|
||||||
# cur_len will be zero, so the next line will be entirely
|
|
||||||
# devoted to the long word that we can't handle right now.
|
|
||||||
|
|
||||||
def _wrap_chunks(self, chunks):
|
|
||||||
"""_wrap_chunks(chunks : [string]) -> [string]
|
|
||||||
|
|
||||||
Wrap a sequence of text chunks and return a list of lines of
|
|
||||||
length 'self.width' or less. (If 'break_long_words' is false,
|
|
||||||
some lines may be longer than this.) Chunks correspond roughly
|
|
||||||
to words and the whitespace between them: each chunk is
|
|
||||||
indivisible (modulo 'break_long_words'), but a line break can
|
|
||||||
come between any two chunks. Chunks should not have internal
|
|
||||||
whitespace; ie. a chunk is either all whitespace or a "word".
|
|
||||||
Whitespace chunks will be removed from the beginning and end of
|
|
||||||
lines, but apart from that whitespace is preserved.
|
|
||||||
"""
|
|
||||||
lines = []
|
|
||||||
if self.width <= 0:
|
|
||||||
raise ValueError("invalid width %r (must be > 0)" % self.width)
|
|
||||||
|
|
||||||
# Arrange in reverse order so items can be efficiently popped
|
|
||||||
# from a stack of chucks.
|
|
||||||
chunks.reverse()
|
|
||||||
|
|
||||||
while chunks:
|
|
||||||
|
|
||||||
# Start the list of chunks that will make up the current line.
|
|
||||||
# cur_len is just the length of all the chunks in cur_line.
|
|
||||||
cur_line = []
|
|
||||||
cur_len = 0
|
|
||||||
|
|
||||||
# Figure out which static string will prefix this line.
|
|
||||||
if lines:
|
|
||||||
indent = self.subsequent_indent
|
|
||||||
else:
|
|
||||||
indent = self.initial_indent
|
|
||||||
|
|
||||||
# Maximum width for this line.
|
|
||||||
width = self.width - len(indent)
|
|
||||||
|
|
||||||
# First chunk on line is whitespace -- drop it, unless this
|
|
||||||
# is the very beginning of the text (ie. no lines started yet).
|
|
||||||
if chunks[-1].strip() == '' and lines:
|
|
||||||
del chunks[-1]
|
|
||||||
|
|
||||||
while chunks:
|
|
||||||
l = len(chunks[-1])
|
|
||||||
|
|
||||||
# Can at least squeeze this chunk onto the current line.
|
|
||||||
if cur_len + l <= width:
|
|
||||||
cur_line.append(chunks.pop())
|
|
||||||
cur_len += l
|
|
||||||
|
|
||||||
# Nope, this line is full.
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
# The current line is full, and the next chunk is too big to
|
|
||||||
# fit on *any* line (not just this one).
|
|
||||||
if chunks and len(chunks[-1]) > width:
|
|
||||||
self._handle_long_word(chunks, cur_line, cur_len, width)
|
|
||||||
|
|
||||||
# If the last chunk on this line is all whitespace, drop it.
|
|
||||||
if cur_line and cur_line[-1].strip() == '':
|
|
||||||
del cur_line[-1]
|
|
||||||
|
|
||||||
# Convert current line back to a string and store it in list
|
|
||||||
# of all lines (return value).
|
|
||||||
if cur_line:
|
|
||||||
lines.append(indent + ''.join(cur_line))
|
|
||||||
|
|
||||||
return lines
|
|
||||||
|
|
||||||
|
|
||||||
# -- Public interface ----------------------------------------------
|
|
||||||
|
|
||||||
def wrap(self, text):
|
|
||||||
"""wrap(text : string) -> [string]
|
|
||||||
|
|
||||||
Reformat the single paragraph in 'text' so it fits in lines of
|
|
||||||
no more than 'self.width' columns, and return a list of wrapped
|
|
||||||
lines. Tabs in 'text' are expanded with string.expandtabs(),
|
|
||||||
and all other whitespace characters (including newline) are
|
|
||||||
converted to space.
|
|
||||||
"""
|
|
||||||
text = self._munge_whitespace(text)
|
|
||||||
chunks = self._split(text)
|
|
||||||
if self.fix_sentence_endings:
|
|
||||||
self._fix_sentence_endings(chunks)
|
|
||||||
return self._wrap_chunks(chunks)
|
|
||||||
|
|
||||||
def fill(self, text):
|
|
||||||
"""fill(text : string) -> string
|
|
||||||
|
|
||||||
Reformat the single paragraph in 'text' to fit in lines of no
|
|
||||||
more than 'self.width' columns, and return a new string
|
|
||||||
containing the entire wrapped paragraph.
|
|
||||||
"""
|
|
||||||
return "\n".join(self.wrap(text))
|
|
||||||
|
|
||||||
|
|
||||||
# -- Convenience interface ---------------------------------------------
|
|
||||||
|
|
||||||
def wrap(text, width=70, **kwargs):
|
|
||||||
"""Wrap a single paragraph of text, returning a list of wrapped lines.
|
|
||||||
|
|
||||||
Reformat the single paragraph in 'text' so it fits in lines of no
|
|
||||||
more than 'width' columns, and return a list of wrapped lines. By
|
|
||||||
default, tabs in 'text' are expanded with string.expandtabs(), and
|
|
||||||
all other whitespace characters (including newline) are converted to
|
|
||||||
space. See TextWrapper class for available keyword args to customize
|
|
||||||
wrapping behaviour.
|
|
||||||
"""
|
|
||||||
w = TextWrapper(width=width, **kwargs)
|
|
||||||
return w.wrap(text)
|
|
||||||
|
|
||||||
def fill(text, width=70, **kwargs):
|
|
||||||
"""Fill a single paragraph of text, returning a new string.
|
|
||||||
|
|
||||||
Reformat the single paragraph in 'text' to fit in lines of no more
|
|
||||||
than 'width' columns, and return a new string containing the entire
|
|
||||||
wrapped paragraph. As with wrap(), tabs are expanded and other
|
|
||||||
whitespace characters converted to space. See TextWrapper class for
|
|
||||||
available keyword args to customize wrapping behaviour.
|
|
||||||
"""
|
|
||||||
w = TextWrapper(width=width, **kwargs)
|
|
||||||
return w.fill(text)
|
|
||||||
|
|
||||||
|
|
||||||
# -- Loosely related functionality -------------------------------------
|
|
||||||
|
|
||||||
def dedent(text):
|
|
||||||
"""dedent(text : string) -> string
|
|
||||||
|
|
||||||
Remove any whitespace than can be uniformly removed from the left
|
|
||||||
of every line in `text`.
|
|
||||||
|
|
||||||
This can be used e.g. to make triple-quoted strings line up with
|
|
||||||
the left edge of screen/whatever, while still presenting it in the
|
|
||||||
source code in indented form.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
def test():
|
|
||||||
# end first line with \ to avoid the empty line!
|
|
||||||
s = '''\
|
|
||||||
hello
|
|
||||||
world
|
|
||||||
'''
|
|
||||||
print repr(s) # prints ' hello\n world\n '
|
|
||||||
print repr(dedent(s)) # prints 'hello\n world\n'
|
|
||||||
"""
|
|
||||||
lines = text.expandtabs().split('\n')
|
|
||||||
margin = None
|
|
||||||
for line in lines:
|
|
||||||
content = line.lstrip()
|
|
||||||
if not content:
|
|
||||||
continue
|
|
||||||
indent = len(line) - len(content)
|
|
||||||
if margin is None:
|
|
||||||
margin = indent
|
|
||||||
else:
|
|
||||||
margin = min(margin, indent)
|
|
||||||
|
|
||||||
if margin is not None and margin > 0:
|
|
||||||
for i in range(len(lines)):
|
|
||||||
lines[i] = lines[i][margin:]
|
|
||||||
|
|
||||||
return '\n'.join(lines)
|
|
|
@ -1,12 +1,8 @@
|
||||||
|
|
||||||
import os, inspect, socket
|
import os, inspect, socket
|
||||||
import sys
|
import sys
|
||||||
from py.magic import autopath ; mypath = autopath()
|
import py
|
||||||
|
|
||||||
try:
|
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
except ImportError:
|
|
||||||
from py.__.compat.subprocess import Popen, PIPE
|
|
||||||
|
|
||||||
import py
|
import py
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
@ -128,8 +124,9 @@ class SocketGateway(InstallableGateway):
|
||||||
host, port = ('', 0) # XXX works on all platforms?
|
host, port = ('', 0) # XXX works on all platforms?
|
||||||
else:
|
else:
|
||||||
host, port = hostport
|
host, port = hostport
|
||||||
|
mydir = py.path.local(__file__).dirpath()
|
||||||
socketserverbootstrap = py.code.Source(
|
socketserverbootstrap = py.code.Source(
|
||||||
mypath.dirpath('script', 'socketserver.py').read('rU'), """
|
mydir.join('script', 'socketserver.py').read('rU'), """
|
||||||
import socket
|
import socket
|
||||||
sock = bind_and_listen((%r, %r))
|
sock = bind_and_listen((%r, %r))
|
||||||
port = sock.getsockname()
|
port = sock.getsockname()
|
||||||
|
|
|
@ -27,6 +27,32 @@ def test_stacklevel():
|
||||||
warning = str(err)
|
warning = str(err)
|
||||||
assert warning.find(":%s" % lno) != -1
|
assert warning.find(":%s" % lno) != -1
|
||||||
|
|
||||||
|
def test_stacklevel_initpkg_with_resolve(testdir):
|
||||||
|
mod = testdir.makepyfile(initpkg="""
|
||||||
|
import py
|
||||||
|
def __getattr__():
|
||||||
|
f()
|
||||||
|
def f():
|
||||||
|
py.log._apiwarn("x", "some", stacklevel="initpkg")
|
||||||
|
""").pyimport()
|
||||||
|
capture = py.io.StdCapture()
|
||||||
|
mod.__getattr__()
|
||||||
|
out, err = capture.reset()
|
||||||
|
lno = test_stacklevel_initpkg_with_resolve.func_code.co_firstlineno + 9
|
||||||
|
warning = str(err)
|
||||||
|
assert warning.find(":%s" % lno) != -1
|
||||||
|
|
||||||
|
def test_stacklevel_initpkg_no_resolve():
|
||||||
|
def f():
|
||||||
|
py.log._apiwarn("x", "some", stacklevel="initpkg")
|
||||||
|
capture = py.io.StdCapture()
|
||||||
|
f()
|
||||||
|
out, err = capture.reset()
|
||||||
|
lno = test_stacklevel_initpkg_no_resolve.func_code.co_firstlineno + 2
|
||||||
|
warning = str(err)
|
||||||
|
assert warning.find(":%s" % lno) != -1
|
||||||
|
|
||||||
|
|
||||||
def test_function():
|
def test_function():
|
||||||
capture = py.io.StdCapture()
|
capture = py.io.StdCapture()
|
||||||
py.log._apiwarn("x.y.z", "something", function=test_function)
|
py.log._apiwarn("x.y.z", "something", function=test_function)
|
||||||
|
|
|
@ -13,6 +13,18 @@ class Warning(py.std.exceptions.DeprecationWarning):
|
||||||
def _apiwarn(startversion, msg, stacklevel=1, function=None):
|
def _apiwarn(startversion, msg, stacklevel=1, function=None):
|
||||||
# below is mostly COPIED from python2.4/warnings.py's def warn()
|
# below is mostly COPIED from python2.4/warnings.py's def warn()
|
||||||
# Get context information
|
# Get context information
|
||||||
|
if stacklevel == "initpkg":
|
||||||
|
frame = sys._getframe(1)
|
||||||
|
level = 2
|
||||||
|
while frame:
|
||||||
|
co = frame.f_code
|
||||||
|
if co.co_name == "__getattr__" and co.co_filename.find("initpkg") !=-1:
|
||||||
|
stacklevel = level
|
||||||
|
break
|
||||||
|
level += 1
|
||||||
|
frame = frame.f_back
|
||||||
|
else:
|
||||||
|
stacklevel = 1
|
||||||
msg = "%s (since version %s)" %(msg, startversion)
|
msg = "%s (since version %s)" %(msg, startversion)
|
||||||
warn(msg, stacklevel=stacklevel+1, function=function)
|
warn(msg, stacklevel=stacklevel+1, function=function)
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,8 @@ class LocalPath(FSBase):
|
||||||
try:
|
try:
|
||||||
import hashlib as mod
|
import hashlib as mod
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
if hashtype == "sha1":
|
||||||
|
hashtype = "sha"
|
||||||
mod = __import__(hashtype)
|
mod = __import__(hashtype)
|
||||||
hash = getattr(mod, hashtype)()
|
hash = getattr(mod, hashtype)()
|
||||||
except (AttributeError, ImportError):
|
except (AttributeError, ImportError):
|
||||||
|
@ -534,7 +536,7 @@ class LocalPath(FSBase):
|
||||||
to be executed. Note that this process is directly
|
to be executed. Note that this process is directly
|
||||||
invoked and not through a system shell.
|
invoked and not through a system shell.
|
||||||
"""
|
"""
|
||||||
from py.compat.subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
argv = map(str, argv)
|
argv = map(str, argv)
|
||||||
proc = Popen([str(self)] + list(argv), stdout=PIPE, stderr=PIPE)
|
proc = Popen([str(self)] + list(argv), stdout=PIPE, stderr=PIPE)
|
||||||
stdout, stderr = proc.communicate()
|
stdout, stderr = proc.communicate()
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Config(object):
|
||||||
""" test configuration object, provides access to config valueso,
|
""" test configuration object, provides access to config valueso,
|
||||||
the pluginmanager and plugin api.
|
the pluginmanager and plugin api.
|
||||||
"""
|
"""
|
||||||
Option = py.compat.optparse.Option # deprecated
|
Option = py.std.optparse.Option
|
||||||
Error = Error
|
Error = Error
|
||||||
basetemp = None
|
basetemp = None
|
||||||
_sessionclass = None
|
_sessionclass = None
|
||||||
|
|
|
@ -14,7 +14,7 @@ for options. basic usage:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
from py.compat import optparse
|
import optparse
|
||||||
|
|
||||||
class Parser:
|
class Parser:
|
||||||
""" Parser for command line arguments. """
|
""" Parser for command line arguments. """
|
||||||
|
@ -76,11 +76,11 @@ class OptionGroup:
|
||||||
|
|
||||||
def addoption(self, *optnames, **attrs):
|
def addoption(self, *optnames, **attrs):
|
||||||
""" add an option to this group. """
|
""" add an option to this group. """
|
||||||
option = py.compat.optparse.Option(*optnames, **attrs)
|
option = optparse.Option(*optnames, **attrs)
|
||||||
self._addoption_instance(option, shortupper=False)
|
self._addoption_instance(option, shortupper=False)
|
||||||
|
|
||||||
def _addoption(self, *optnames, **attrs):
|
def _addoption(self, *optnames, **attrs):
|
||||||
option = py.compat.optparse.Option(*optnames, **attrs)
|
option = optparse.Option(*optnames, **attrs)
|
||||||
self._addoption_instance(option, shortupper=True)
|
self._addoption_instance(option, shortupper=True)
|
||||||
|
|
||||||
def _addoption_instance(self, option, shortupper=False):
|
def _addoption_instance(self, option, shortupper=False):
|
||||||
|
|
|
@ -15,6 +15,7 @@ as well.
|
||||||
|
|
||||||
import py
|
import py
|
||||||
from py.__.code.code import TerminalRepr, ReprFileLocation
|
from py.__.code.code import TerminalRepr, ReprFileLocation
|
||||||
|
import doctest
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
group = parser.addgroup("doctest options")
|
group = parser.addgroup("doctest options")
|
||||||
|
@ -46,7 +47,7 @@ class DoctestItem(py.test.collect.Item):
|
||||||
self.fspath = path
|
self.fspath = path
|
||||||
|
|
||||||
def repr_failure(self, excinfo):
|
def repr_failure(self, excinfo):
|
||||||
if excinfo.errisinstance(py.compat.doctest.DocTestFailure):
|
if excinfo.errisinstance(doctest.DocTestFailure):
|
||||||
doctestfailure = excinfo.value
|
doctestfailure = excinfo.value
|
||||||
example = doctestfailure.example
|
example = doctestfailure.example
|
||||||
test = doctestfailure.test
|
test = doctestfailure.test
|
||||||
|
@ -54,8 +55,8 @@ class DoctestItem(py.test.collect.Item):
|
||||||
lineno = test.lineno + example.lineno + 1
|
lineno = test.lineno + example.lineno + 1
|
||||||
message = excinfo.type.__name__
|
message = excinfo.type.__name__
|
||||||
reprlocation = ReprFileLocation(filename, lineno, message)
|
reprlocation = ReprFileLocation(filename, lineno, message)
|
||||||
checker = py.compat.doctest.OutputChecker()
|
checker = doctest.OutputChecker()
|
||||||
REPORT_UDIFF = py.compat.doctest.REPORT_UDIFF
|
REPORT_UDIFF = doctest.REPORT_UDIFF
|
||||||
filelines = py.path.local(filename).readlines(cr=0)
|
filelines = py.path.local(filename).readlines(cr=0)
|
||||||
i = max(test.lineno, max(0, lineno - 10)) # XXX?
|
i = max(test.lineno, max(0, lineno - 10)) # XXX?
|
||||||
lines = []
|
lines = []
|
||||||
|
@ -65,7 +66,7 @@ class DoctestItem(py.test.collect.Item):
|
||||||
lines += checker.output_difference(example,
|
lines += checker.output_difference(example,
|
||||||
doctestfailure.got, REPORT_UDIFF).split("\n")
|
doctestfailure.got, REPORT_UDIFF).split("\n")
|
||||||
return ReprFailDoctest(reprlocation, lines)
|
return ReprFailDoctest(reprlocation, lines)
|
||||||
elif excinfo.errisinstance(py.compat.doctest.UnexpectedException):
|
elif excinfo.errisinstance(doctest.UnexpectedException):
|
||||||
excinfo = py.code.ExceptionInfo(excinfo.value.exc_info)
|
excinfo = py.code.ExceptionInfo(excinfo.value.exc_info)
|
||||||
return super(DoctestItem, self).repr_failure(excinfo)
|
return super(DoctestItem, self).repr_failure(excinfo)
|
||||||
else:
|
else:
|
||||||
|
@ -74,14 +75,14 @@ class DoctestItem(py.test.collect.Item):
|
||||||
class DoctestTextfile(DoctestItem):
|
class DoctestTextfile(DoctestItem):
|
||||||
def runtest(self):
|
def runtest(self):
|
||||||
if not self._deprecated_testexecution():
|
if not self._deprecated_testexecution():
|
||||||
failed, tot = py.compat.doctest.testfile(
|
failed, tot = doctest.testfile(
|
||||||
str(self.fspath), module_relative=False,
|
str(self.fspath), module_relative=False,
|
||||||
raise_on_error=True, verbose=0)
|
raise_on_error=True, verbose=0)
|
||||||
|
|
||||||
class DoctestModule(DoctestItem):
|
class DoctestModule(DoctestItem):
|
||||||
def runtest(self):
|
def runtest(self):
|
||||||
module = self.fspath.pyimport()
|
module = self.fspath.pyimport()
|
||||||
failed, tot = py.compat.doctest.testmod(
|
failed, tot = doctest.testmod(
|
||||||
module, raise_on_error=True, verbose=0)
|
module, raise_on_error=True, verbose=0)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,7 @@ class DoctestText(py.test.collect.Item):
|
||||||
l.append(line)
|
l.append(line)
|
||||||
docstring = "\n".join(l)
|
docstring = "\n".join(l)
|
||||||
mod.__doc__ = docstring
|
mod.__doc__ = docstring
|
||||||
failed, tot = py.compat.doctest.testmod(mod, verbose=1)
|
failed, tot = py.std.doctest.testmod(mod, verbose=1)
|
||||||
if failed:
|
if failed:
|
||||||
py.test.fail("doctest %s: %s failed out of %s" %(
|
py.test.fail("doctest %s: %s failed out of %s" %(
|
||||||
self.fspath, failed, tot))
|
self.fspath, failed, tot))
|
||||||
|
|
|
@ -30,7 +30,7 @@ class TestParser:
|
||||||
group = parseopt.OptionGroup("hello")
|
group = parseopt.OptionGroup("hello")
|
||||||
group.addoption("--option1", action="store_true")
|
group.addoption("--option1", action="store_true")
|
||||||
assert len(group.options) == 1
|
assert len(group.options) == 1
|
||||||
assert isinstance(group.options[0], py.compat.optparse.Option)
|
assert isinstance(group.options[0], parseopt.optparse.Option)
|
||||||
|
|
||||||
def test_group_shortopt_lowercase(self):
|
def test_group_shortopt_lowercase(self):
|
||||||
parser = parseopt.Parser()
|
parser = parseopt.Parser()
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import py,sys
|
import py,sys
|
||||||
py.test.skip("implementation missing: recording")
|
|
||||||
|
|
||||||
class TestRecordingAccept:
|
class TestRecordingAccept:
|
||||||
def test_recording_and_back(self, testdir):
|
def test_recording_and_back(self, testdir):
|
||||||
|
py.test.skip("implementation missing: recording")
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
import py
|
import py
|
||||||
def test_fail():
|
def test_fail():
|
||||||
|
|
Loading…
Reference in New Issue