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
|
||||
self.h2("command line options")
|
||||
self.Print()
|
||||
formatter = py.compat.optparse.IndentedHelpFormatter()
|
||||
formatter = py.std.optparse.IndentedHelpFormatter()
|
||||
for opt in options:
|
||||
switches = formatter.format_option_strings(opt)
|
||||
self.Print("``%s``" % switches)
|
||||
|
|
|
@ -7,9 +7,8 @@ obtain system info from remote machine.
|
|||
import py
|
||||
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,
|
||||
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,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
Changes between 1.0.x and 'trunk'
|
||||
=====================================
|
||||
|
||||
* deprecate py.compat.doctest|subprocess|textwrap|optparse
|
||||
|
||||
* deprecate py.magic.autopath, remove py/magic directory
|
||||
|
||||
* 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:
|
||||
|
||||
* :source:`py/compat/`
|
||||
* :source:`py/builtin/`
|
||||
|
||||
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`
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -7,9 +7,8 @@ obtain system info from remote machine.
|
|||
import py
|
||||
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,
|
||||
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,
|
||||
|
|
|
@ -191,12 +191,12 @@ initpkg(__name__,
|
|||
'log.STDERR' : ('./log/log.py', 'STDERR'),
|
||||
'log.Syslog' : ('./log/log.py', 'Syslog'),
|
||||
|
||||
# compatibility modules (taken from 2.4.4)
|
||||
# compatibility modules (deprecated)
|
||||
'compat.__doc__' : ('./compat/__init__.py', '__doc__'),
|
||||
'compat.doctest' : ('./compat/doctest.py', '*'),
|
||||
'compat.optparse' : ('./compat/optparse.py', '*'),
|
||||
'compat.textwrap' : ('./compat/textwrap.py', '*'),
|
||||
'compat.subprocess' : ('./compat/subprocess.py', '*'),
|
||||
'compat.doctest' : ('./compat/dep_doctest.py', 'doctest'),
|
||||
'compat.optparse' : ('./compat/dep_optparse.py', 'optparse'),
|
||||
'compat.textwrap' : ('./compat/dep_textwrap.py', 'textwrap'),
|
||||
'compat.subprocess' : ('./compat/dep_subprocess.py', 'subprocess'),
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ a ".".
|
|||
import py
|
||||
|
||||
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",
|
||||
help="remove files with the given comma-separated list of extensions"
|
||||
)
|
||||
|
|
|
@ -191,7 +191,7 @@ def main():
|
|||
import py
|
||||
|
||||
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):
|
||||
if hasattr(optparser, 'output'):
|
||||
|
|
|
@ -12,10 +12,9 @@ current working directory). Distinguish between test files and normal ones and
|
|||
report them separately.
|
||||
"""
|
||||
import py
|
||||
from py.compat import optparse
|
||||
|
||||
def main():
|
||||
parser = optparse.OptionParser(usage=__doc__)
|
||||
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||
(options, args) = parser.parse_args()
|
||||
countloc(args)
|
||||
|
||||
|
|
|
@ -16,9 +16,7 @@ curdir = py.path.local()
|
|||
def rec(p):
|
||||
return p.check(dotfile=0)
|
||||
|
||||
optparse = py.compat.optparse
|
||||
|
||||
parser = optparse.OptionParser(usage=__doc__)
|
||||
parser = py.std.optparse.OptionParser(usage=__doc__)
|
||||
parser.add_option("-i", "--ignore-case", action="store_true", dest="ignorecase",
|
||||
help="ignore case distinctions")
|
||||
parser.add_option("-C", "--context", action="store", type="int", dest="context",
|
||||
|
|
|
@ -22,9 +22,8 @@ else:
|
|||
def log(msg):
|
||||
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,
|
||||
help="generate pdf files")
|
||||
parser.add_option("--stylesheet", dest="stylesheet", default=None,
|
||||
|
|
|
@ -41,9 +41,8 @@ def svnwcrevert(path, root=None, precious=[]):
|
|||
svnwcrevert(p, root)
|
||||
|
||||
# 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",
|
||||
action="append", dest="precious", default=[],
|
||||
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 sys
|
||||
from py.magic import autopath ; mypath = autopath()
|
||||
|
||||
try:
|
||||
from subprocess import Popen, PIPE
|
||||
except ImportError:
|
||||
from py.__.compat.subprocess import Popen, PIPE
|
||||
import py
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
import py
|
||||
if sys.platform == "win32":
|
||||
|
@ -128,8 +124,9 @@ class SocketGateway(InstallableGateway):
|
|||
host, port = ('', 0) # XXX works on all platforms?
|
||||
else:
|
||||
host, port = hostport
|
||||
mydir = py.path.local(__file__).dirpath()
|
||||
socketserverbootstrap = py.code.Source(
|
||||
mypath.dirpath('script', 'socketserver.py').read('rU'), """
|
||||
mydir.join('script', 'socketserver.py').read('rU'), """
|
||||
import socket
|
||||
sock = bind_and_listen((%r, %r))
|
||||
port = sock.getsockname()
|
||||
|
|
|
@ -27,6 +27,32 @@ def test_stacklevel():
|
|||
warning = str(err)
|
||||
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():
|
||||
capture = py.io.StdCapture()
|
||||
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):
|
||||
# below is mostly COPIED from python2.4/warnings.py's def warn()
|
||||
# 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)
|
||||
warn(msg, stacklevel=stacklevel+1, function=function)
|
||||
|
||||
|
|
|
@ -165,6 +165,8 @@ class LocalPath(FSBase):
|
|||
try:
|
||||
import hashlib as mod
|
||||
except ImportError:
|
||||
if hashtype == "sha1":
|
||||
hashtype = "sha"
|
||||
mod = __import__(hashtype)
|
||||
hash = getattr(mod, hashtype)()
|
||||
except (AttributeError, ImportError):
|
||||
|
@ -534,7 +536,7 @@ class LocalPath(FSBase):
|
|||
to be executed. Note that this process is directly
|
||||
invoked and not through a system shell.
|
||||
"""
|
||||
from py.compat.subprocess import Popen, PIPE
|
||||
from subprocess import Popen, PIPE
|
||||
argv = map(str, argv)
|
||||
proc = Popen([str(self)] + list(argv), stdout=PIPE, stderr=PIPE)
|
||||
stdout, stderr = proc.communicate()
|
||||
|
|
|
@ -23,7 +23,7 @@ class Config(object):
|
|||
""" test configuration object, provides access to config valueso,
|
||||
the pluginmanager and plugin api.
|
||||
"""
|
||||
Option = py.compat.optparse.Option # deprecated
|
||||
Option = py.std.optparse.Option
|
||||
Error = Error
|
||||
basetemp = None
|
||||
_sessionclass = None
|
||||
|
|
|
@ -14,7 +14,7 @@ for options. basic usage:
|
|||
|
||||
"""
|
||||
import py
|
||||
from py.compat import optparse
|
||||
import optparse
|
||||
|
||||
class Parser:
|
||||
""" Parser for command line arguments. """
|
||||
|
@ -76,11 +76,11 @@ class OptionGroup:
|
|||
|
||||
def addoption(self, *optnames, **attrs):
|
||||
""" add an option to this group. """
|
||||
option = py.compat.optparse.Option(*optnames, **attrs)
|
||||
option = optparse.Option(*optnames, **attrs)
|
||||
self._addoption_instance(option, shortupper=False)
|
||||
|
||||
def _addoption(self, *optnames, **attrs):
|
||||
option = py.compat.optparse.Option(*optnames, **attrs)
|
||||
option = optparse.Option(*optnames, **attrs)
|
||||
self._addoption_instance(option, shortupper=True)
|
||||
|
||||
def _addoption_instance(self, option, shortupper=False):
|
||||
|
|
|
@ -15,6 +15,7 @@ as well.
|
|||
|
||||
import py
|
||||
from py.__.code.code import TerminalRepr, ReprFileLocation
|
||||
import doctest
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.addgroup("doctest options")
|
||||
|
@ -46,7 +47,7 @@ class DoctestItem(py.test.collect.Item):
|
|||
self.fspath = path
|
||||
|
||||
def repr_failure(self, excinfo):
|
||||
if excinfo.errisinstance(py.compat.doctest.DocTestFailure):
|
||||
if excinfo.errisinstance(doctest.DocTestFailure):
|
||||
doctestfailure = excinfo.value
|
||||
example = doctestfailure.example
|
||||
test = doctestfailure.test
|
||||
|
@ -54,8 +55,8 @@ class DoctestItem(py.test.collect.Item):
|
|||
lineno = test.lineno + example.lineno + 1
|
||||
message = excinfo.type.__name__
|
||||
reprlocation = ReprFileLocation(filename, lineno, message)
|
||||
checker = py.compat.doctest.OutputChecker()
|
||||
REPORT_UDIFF = py.compat.doctest.REPORT_UDIFF
|
||||
checker = doctest.OutputChecker()
|
||||
REPORT_UDIFF = doctest.REPORT_UDIFF
|
||||
filelines = py.path.local(filename).readlines(cr=0)
|
||||
i = max(test.lineno, max(0, lineno - 10)) # XXX?
|
||||
lines = []
|
||||
|
@ -65,7 +66,7 @@ class DoctestItem(py.test.collect.Item):
|
|||
lines += checker.output_difference(example,
|
||||
doctestfailure.got, REPORT_UDIFF).split("\n")
|
||||
return ReprFailDoctest(reprlocation, lines)
|
||||
elif excinfo.errisinstance(py.compat.doctest.UnexpectedException):
|
||||
elif excinfo.errisinstance(doctest.UnexpectedException):
|
||||
excinfo = py.code.ExceptionInfo(excinfo.value.exc_info)
|
||||
return super(DoctestItem, self).repr_failure(excinfo)
|
||||
else:
|
||||
|
@ -74,14 +75,14 @@ class DoctestItem(py.test.collect.Item):
|
|||
class DoctestTextfile(DoctestItem):
|
||||
def runtest(self):
|
||||
if not self._deprecated_testexecution():
|
||||
failed, tot = py.compat.doctest.testfile(
|
||||
failed, tot = doctest.testfile(
|
||||
str(self.fspath), module_relative=False,
|
||||
raise_on_error=True, verbose=0)
|
||||
|
||||
class DoctestModule(DoctestItem):
|
||||
def runtest(self):
|
||||
module = self.fspath.pyimport()
|
||||
failed, tot = py.compat.doctest.testmod(
|
||||
failed, tot = doctest.testmod(
|
||||
module, raise_on_error=True, verbose=0)
|
||||
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ class DoctestText(py.test.collect.Item):
|
|||
l.append(line)
|
||||
docstring = "\n".join(l)
|
||||
mod.__doc__ = docstring
|
||||
failed, tot = py.compat.doctest.testmod(mod, verbose=1)
|
||||
failed, tot = py.std.doctest.testmod(mod, verbose=1)
|
||||
if failed:
|
||||
py.test.fail("doctest %s: %s failed out of %s" %(
|
||||
self.fspath, failed, tot))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import py
|
||||
from py.__.test import parseopt
|
||||
from py.__.test import parseopt
|
||||
|
||||
class TestParser:
|
||||
def test_init(self, capsys):
|
||||
|
@ -30,7 +30,7 @@ class TestParser:
|
|||
group = parseopt.OptionGroup("hello")
|
||||
group.addoption("--option1", action="store_true")
|
||||
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):
|
||||
parser = parseopt.Parser()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import py,sys
|
||||
py.test.skip("implementation missing: recording")
|
||||
|
||||
class TestRecordingAccept:
|
||||
def test_recording_and_back(self, testdir):
|
||||
py.test.skip("implementation missing: recording")
|
||||
p = testdir.makepyfile("""
|
||||
import py
|
||||
def test_fail():
|
||||
|
|
Loading…
Reference in New Issue