Merged revisions 61038,61042-61045,61047,61050,61053,61055-61056,61061-61062,61066,61068,61070,61081-61095 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r61081 | neal.norwitz | 2008-02-26 09:04:59 +0100 (Tue, 26 Feb 2008) | 7 lines Speed up this test by about 99%. Remove sleeps and replace with events. (This may fail on some slow platforms, but we can fix those cases which should be relatively isolated and easier to find now.) Move two test cases that didn't require a server to be started to a separate TestCase. These tests were taking 3 seconds which is what the timeout was set to. ........ r61082 | christian.heimes | 2008-02-26 09:18:11 +0100 (Tue, 26 Feb 2008) | 1 line The contains function raised a gcc warning. The new code is copied straight from py3k. ........ r61084 | neal.norwitz | 2008-02-26 09:21:28 +0100 (Tue, 26 Feb 2008) | 3 lines Add a timing flag to Trace so you can see where slowness occurs like waiting for socket timeouts in test_smtplib :-). ........ r61086 | christian.heimes | 2008-02-26 18:23:51 +0100 (Tue, 26 Feb 2008) | 3 lines Patch #1691070 from Roger Upole: Speed up PyArg_ParseTupleAndKeywords() and improve error msg My tests don't show the promised speed up of 10%. The code is as fast as the old code for simple cases and slightly faster for complex cases with several of args and kwargs. But the patch simplifies the code, too. ........ r61087 | georg.brandl | 2008-02-26 20:13:45 +0100 (Tue, 26 Feb 2008) | 2 lines #2194: fix some typos. ........ r61088 | raymond.hettinger | 2008-02-27 00:40:50 +0100 (Wed, 27 Feb 2008) | 1 line Add itertools.combinations(). ........ r61089 | raymond.hettinger | 2008-02-27 02:08:04 +0100 (Wed, 27 Feb 2008) | 1 line One too many decrefs. ........ r61090 | raymond.hettinger | 2008-02-27 02:08:30 +0100 (Wed, 27 Feb 2008) | 1 line Larger test range ........ r61091 | raymond.hettinger | 2008-02-27 02:44:34 +0100 (Wed, 27 Feb 2008) | 1 line Simply the sample code for combinations(). ........
This commit is contained in:
parent
1041f74837
commit
380f7f22fa
|
@ -95,21 +95,20 @@ loops that truncate the stream.
|
||||||
|
|
||||||
def combinations(iterable, r):
|
def combinations(iterable, r):
|
||||||
pool = tuple(iterable)
|
pool = tuple(iterable)
|
||||||
if pool:
|
|
||||||
n = len(pool)
|
n = len(pool)
|
||||||
|
assert 0 <= r <= n
|
||||||
vec = range(r)
|
vec = range(r)
|
||||||
yield tuple(pool[i] for i in vec)
|
yield tuple(pool[i] for i in vec)
|
||||||
while 1:
|
while 1:
|
||||||
for i in reversed(range(r)):
|
for i in reversed(range(r)):
|
||||||
if vec[i] == i + n-r:
|
if vec[i] != i + n - r:
|
||||||
continue
|
break
|
||||||
|
else:
|
||||||
|
return
|
||||||
vec[i] += 1
|
vec[i] += 1
|
||||||
for j in range(i+1, r):
|
for j in range(i+1, r):
|
||||||
vec[j] = vec[j-1] + 1
|
vec[j] = vec[j-1] + 1
|
||||||
yield tuple(pool[i] for i in vec)
|
yield tuple(pool[i] for i in vec)
|
||||||
break
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ Programming Interface
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
||||||
.. class:: Trace([count=1[, trace=1[, countfuncs=0[, countcallers=0[, ignoremods=()[, ignoredirs=()[, infile=None[, outfile=None]]]]]]]])
|
.. class:: Trace([count=1[, trace=1[, countfuncs=0[, countcallers=0[, ignoremods=()[, ignoredirs=()[, infile=None[, outfile=None[, timing=False]]]]]]]]])
|
||||||
|
|
||||||
Create an object to trace execution of a single statement or expression. All
|
Create an object to trace execution of a single statement or expression. All
|
||||||
parameters are optional. *count* enables counting of line numbers. *trace*
|
parameters are optional. *count* enables counting of line numbers. *trace*
|
||||||
|
@ -89,7 +89,8 @@ Programming Interface
|
||||||
*ignoremods* is a list of modules or packages to ignore. *ignoredirs* is a list
|
*ignoremods* is a list of modules or packages to ignore. *ignoredirs* is a list
|
||||||
of directories whose modules or packages should be ignored. *infile* is the
|
of directories whose modules or packages should be ignored. *infile* is the
|
||||||
file from which to read stored count information. *outfile* is a file in which
|
file from which to read stored count information. *outfile* is a file in which
|
||||||
to write updated count information.
|
to write updated count information. *timing* enables a timestamp relative
|
||||||
|
to when tracing was started to be displayed.
|
||||||
|
|
||||||
|
|
||||||
.. method:: Trace.run(cmd)
|
.. method:: Trace.run(cmd)
|
||||||
|
|
|
@ -20,7 +20,7 @@ package on all others. However there are certain features you might want to use
|
||||||
that are not available on your distro's package. You can easily compile the
|
that are not available on your distro's package. You can easily compile the
|
||||||
latest version of Python from source.
|
latest version of Python from source.
|
||||||
|
|
||||||
In the event Python doesn't come preinstalled and isn't in the repositories as
|
In the event that Python doesn't come preinstalled and isn't in the repositories as
|
||||||
well, you can easily make packages for your own distro. Have a look at the
|
well, you can easily make packages for your own distro. Have a look at the
|
||||||
following links:
|
following links:
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ has compiled Windows installers (MSI packages) with every `release
|
||||||
<http://www.python.org/download/releases/>`_ for many years.
|
<http://www.python.org/download/releases/>`_ for many years.
|
||||||
|
|
||||||
With ongoing development of Python, some platforms that used to be supported
|
With ongoing development of Python, some platforms that used to be supported
|
||||||
earlier are not longer supported (due to the lack of users or developers).
|
earlier are no longer supported (due to the lack of users or developers).
|
||||||
Check :pep:`11` for details on all unsupported platforms.
|
Check :pep:`11` for details on all unsupported platforms.
|
||||||
|
|
||||||
* DOS and Windows 3.x are deprecated since Python 2.0 and code specific to these
|
* DOS and Windows 3.x are deprecated since Python 2.0 and code specific to these
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import unittest
|
import unittest
|
||||||
from test import test_support
|
from test import test_support
|
||||||
|
from _testcapi import getargs_keywords
|
||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
warnings.filterwarnings("ignore",
|
warnings.filterwarnings("ignore",
|
||||||
|
@ -248,9 +249,57 @@ class Tuple_TestCase(unittest.TestCase):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
self.assertRaises(TypeError, getargs_tuple, 1, seq())
|
self.assertRaises(TypeError, getargs_tuple, 1, seq())
|
||||||
|
|
||||||
|
class Keywords_TestCase(unittest.TestCase):
|
||||||
|
def test_positional_args(self):
|
||||||
|
# using all positional args
|
||||||
|
self.assertEquals(
|
||||||
|
getargs_keywords((1,2), 3, (4,(5,6)), (7,8,9), 10),
|
||||||
|
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
|
)
|
||||||
|
def test_mixed_args(self):
|
||||||
|
# positional and keyword args
|
||||||
|
self.assertEquals(
|
||||||
|
getargs_keywords((1,2), 3, (4,(5,6)), arg4=(7,8,9), arg5=10),
|
||||||
|
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
|
)
|
||||||
|
def test_keyword_args(self):
|
||||||
|
# all keywords
|
||||||
|
self.assertEquals(
|
||||||
|
getargs_keywords(arg1=(1,2), arg2=3, arg3=(4,(5,6)), arg4=(7,8,9), arg5=10),
|
||||||
|
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
|
)
|
||||||
|
def test_optional_args(self):
|
||||||
|
# missing optional keyword args, skipping tuples
|
||||||
|
self.assertEquals(
|
||||||
|
getargs_keywords(arg1=(1,2), arg2=3, arg5=10),
|
||||||
|
(1, 2, 3, -1, -1, -1, -1, -1, -1, 10)
|
||||||
|
)
|
||||||
|
def test_required_args(self):
|
||||||
|
# required arg missing
|
||||||
|
try:
|
||||||
|
getargs_keywords(arg1=(1,2))
|
||||||
|
except TypeError as err:
|
||||||
|
self.assertEquals(str(err), "Required argument 'arg2' (pos 2) not found")
|
||||||
|
else:
|
||||||
|
self.fail('TypeError should have been raised')
|
||||||
|
def test_too_many_args(self):
|
||||||
|
try:
|
||||||
|
getargs_keywords((1,2),3,(4,(5,6)),(7,8,9),10,111)
|
||||||
|
except TypeError as err:
|
||||||
|
self.assertEquals(str(err), "function takes at most 5 arguments (6 given)")
|
||||||
|
else:
|
||||||
|
self.fail('TypeError should have been raised')
|
||||||
|
def test_invalid_keyword(self):
|
||||||
|
# extraneous keyword arg
|
||||||
|
try:
|
||||||
|
getargs_keywords((1,2),3,arg5=10,arg666=666)
|
||||||
|
except TypeError as err:
|
||||||
|
self.assertEquals(str(err), "'arg666' is an invalid keyword argument for this function")
|
||||||
|
else:
|
||||||
|
self.fail('TypeError should have been raised')
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
tests = [Signed_TestCase, Unsigned_TestCase, Tuple_TestCase]
|
tests = [Signed_TestCase, Unsigned_TestCase, Tuple_TestCase, Keywords_TestCase]
|
||||||
try:
|
try:
|
||||||
from _testcapi import getargs_L, getargs_K
|
from _testcapi import getargs_L, getargs_K
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
@ -44,6 +44,10 @@ def take(n, seq):
|
||||||
'Convenience function for partially consuming a long of infinite iterable'
|
'Convenience function for partially consuming a long of infinite iterable'
|
||||||
return list(islice(seq, n))
|
return list(islice(seq, n))
|
||||||
|
|
||||||
|
def fact(n):
|
||||||
|
'Factorial'
|
||||||
|
return reduce(operator.mul, range(1, n+1), 1)
|
||||||
|
|
||||||
class TestBasicOps(unittest.TestCase):
|
class TestBasicOps(unittest.TestCase):
|
||||||
def test_chain(self):
|
def test_chain(self):
|
||||||
self.assertEqual(list(chain('abc', 'def')), list('abcdef'))
|
self.assertEqual(list(chain('abc', 'def')), list('abcdef'))
|
||||||
|
@ -52,6 +56,26 @@ class TestBasicOps(unittest.TestCase):
|
||||||
self.assertEqual(take(4, chain('abc', 'def')), list('abcd'))
|
self.assertEqual(take(4, chain('abc', 'def')), list('abcd'))
|
||||||
self.assertRaises(TypeError, chain, 2, 3)
|
self.assertRaises(TypeError, chain, 2, 3)
|
||||||
|
|
||||||
|
def test_combinations(self):
|
||||||
|
self.assertRaises(TypeError, combinations, 'abc') # missing r argument
|
||||||
|
self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments
|
||||||
|
self.assertRaises(ValueError, combinations, 'abc', -2) # r is negative
|
||||||
|
self.assertRaises(ValueError, combinations, 'abc', 32) # r is too big
|
||||||
|
self.assertEqual(list(combinations(range(4), 3)),
|
||||||
|
[(0,1,2), (0,1,3), (0,2,3), (1,2,3)])
|
||||||
|
for n in range(8):
|
||||||
|
values = [5*x-12 for x in range(n)]
|
||||||
|
for r in range(n+1):
|
||||||
|
result = list(combinations(values, r))
|
||||||
|
self.assertEqual(len(result), fact(n) / fact(r) / fact(n-r)) # right number of combs
|
||||||
|
self.assertEqual(len(result), len(set(result))) # no repeats
|
||||||
|
self.assertEqual(result, sorted(result)) # lexicographic order
|
||||||
|
for c in result:
|
||||||
|
self.assertEqual(len(c), r) # r-length combinations
|
||||||
|
self.assertEqual(len(set(c)), r) # no duplicate elements
|
||||||
|
self.assertEqual(list(c), sorted(c)) # keep original ordering
|
||||||
|
self.assert_(all(e in values for e in c)) # elements taken from input iterable
|
||||||
|
|
||||||
def test_count(self):
|
def test_count(self):
|
||||||
self.assertEqual(lzip('abc',count()), [('a', 0), ('b', 1), ('c', 2)])
|
self.assertEqual(lzip('abc',count()), [('a', 0), ('b', 1), ('c', 2)])
|
||||||
self.assertEqual(lzip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)])
|
self.assertEqual(lzip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)])
|
||||||
|
|
|
@ -18,14 +18,15 @@ HOST = "localhost"
|
||||||
PORT = None
|
PORT = None
|
||||||
|
|
||||||
def server(evt, buf):
|
def server(evt, buf):
|
||||||
try:
|
|
||||||
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
serv.settimeout(3)
|
serv.settimeout(1)
|
||||||
serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
serv.bind(("", 0))
|
serv.bind(("", 0))
|
||||||
global PORT
|
global PORT
|
||||||
PORT = serv.getsockname()[1]
|
PORT = serv.getsockname()[1]
|
||||||
serv.listen(5)
|
serv.listen(5)
|
||||||
|
evt.set()
|
||||||
|
try:
|
||||||
conn, addr = serv.accept()
|
conn, addr = serv.accept()
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
pass
|
pass
|
||||||
|
@ -38,7 +39,6 @@ def server(evt, buf):
|
||||||
buf = buf[sent:]
|
buf = buf[sent:]
|
||||||
|
|
||||||
n -= 1
|
n -= 1
|
||||||
time.sleep(0.01)
|
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
finally:
|
finally:
|
||||||
|
@ -52,16 +52,8 @@ class GeneralTests(TestCase):
|
||||||
self.evt = threading.Event()
|
self.evt = threading.Event()
|
||||||
servargs = (self.evt, b"220 Hola mundo\n")
|
servargs = (self.evt, b"220 Hola mundo\n")
|
||||||
threading.Thread(target=server, args=servargs).start()
|
threading.Thread(target=server, args=servargs).start()
|
||||||
|
self.evt.wait()
|
||||||
# wait until server thread has assigned a port number
|
self.evt.clear()
|
||||||
n = 500
|
|
||||||
while PORT is None and n > 0:
|
|
||||||
time.sleep(0.01)
|
|
||||||
n -= 1
|
|
||||||
|
|
||||||
# wait a little longer (sometimes connections are refused
|
|
||||||
# on slow machines without this additional wait)
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.evt.wait()
|
self.evt.wait()
|
||||||
|
@ -76,29 +68,12 @@ class GeneralTests(TestCase):
|
||||||
smtp = smtplib.SMTP("%s:%s" % (HOST, PORT))
|
smtp = smtplib.SMTP("%s:%s" % (HOST, PORT))
|
||||||
smtp.sock.close()
|
smtp.sock.close()
|
||||||
|
|
||||||
def testNotConnected(self):
|
|
||||||
# Test various operations on an unconnected SMTP object that
|
|
||||||
# should raise exceptions (at present the attempt in SMTP.send
|
|
||||||
# to reference the nonexistent 'sock' attribute of the SMTP object
|
|
||||||
# causes an AttributeError)
|
|
||||||
smtp = smtplib.SMTP()
|
|
||||||
self.assertRaises(smtplib.SMTPServerDisconnected, smtp.ehlo)
|
|
||||||
self.assertRaises(smtplib.SMTPServerDisconnected,
|
|
||||||
smtp.send, 'test msg')
|
|
||||||
|
|
||||||
def testLocalHostName(self):
|
def testLocalHostName(self):
|
||||||
# check that supplied local_hostname is used
|
# check that supplied local_hostname is used
|
||||||
smtp = smtplib.SMTP(HOST, PORT, local_hostname="testhost")
|
smtp = smtplib.SMTP(HOST, PORT, local_hostname="testhost")
|
||||||
self.assertEqual(smtp.local_hostname, "testhost")
|
self.assertEqual(smtp.local_hostname, "testhost")
|
||||||
smtp.sock.close()
|
smtp.sock.close()
|
||||||
|
|
||||||
def testNonnumericPort(self):
|
|
||||||
# check that non-numeric port raises socket.error
|
|
||||||
self.assertRaises(socket.error, smtplib.SMTP,
|
|
||||||
"localhost", "bogus")
|
|
||||||
self.assertRaises(socket.error, smtplib.SMTP,
|
|
||||||
"localhost:bogus")
|
|
||||||
|
|
||||||
def testTimeoutDefault(self):
|
def testTimeoutDefault(self):
|
||||||
# default
|
# default
|
||||||
smtp = smtplib.SMTP(HOST, PORT)
|
smtp = smtplib.SMTP(HOST, PORT)
|
||||||
|
@ -128,6 +103,7 @@ def debugging_server(server_class, serv_evt, client_evt):
|
||||||
serv = server_class(("", 0), ('nowhere', -1))
|
serv = server_class(("", 0), ('nowhere', -1))
|
||||||
global PORT
|
global PORT
|
||||||
PORT = serv.getsockname()[1]
|
PORT = serv.getsockname()[1]
|
||||||
|
serv_evt.set()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if hasattr(select, 'poll'):
|
if hasattr(select, 'poll'):
|
||||||
|
@ -150,12 +126,12 @@ def debugging_server(server_class, serv_evt, client_evt):
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
|
if not client_evt.isSet():
|
||||||
# allow some time for the client to read the result
|
# allow some time for the client to read the result
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
serv.close()
|
serv.close()
|
||||||
asyncore.close_all()
|
asyncore.close_all()
|
||||||
PORT = None
|
PORT = None
|
||||||
time.sleep(0.5)
|
|
||||||
serv_evt.set()
|
serv_evt.set()
|
||||||
|
|
||||||
MSG_BEGIN = '---------- MESSAGE FOLLOWS ----------\n'
|
MSG_BEGIN = '---------- MESSAGE FOLLOWS ----------\n'
|
||||||
|
@ -181,14 +157,8 @@ class DebuggingServerTests(TestCase):
|
||||||
threading.Thread(target=debugging_server, args=serv_args).start()
|
threading.Thread(target=debugging_server, args=serv_args).start()
|
||||||
|
|
||||||
# wait until server thread has assigned a port number
|
# wait until server thread has assigned a port number
|
||||||
n = 500
|
self.serv_evt.wait()
|
||||||
while PORT is None and n > 0:
|
self.serv_evt.clear()
|
||||||
time.sleep(0.01)
|
|
||||||
n -= 1
|
|
||||||
|
|
||||||
# wait a little longer (sometimes connections are refused
|
|
||||||
# on slow machines without this additional wait)
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# indicate that the client is finished
|
# indicate that the client is finished
|
||||||
|
@ -258,6 +228,26 @@ class DebuggingServerTests(TestCase):
|
||||||
self.assertEqual(self.output.getvalue(), mexpect)
|
self.assertEqual(self.output.getvalue(), mexpect)
|
||||||
|
|
||||||
|
|
||||||
|
class NonConnectingTests(TestCase):
|
||||||
|
|
||||||
|
def testNotConnected(self):
|
||||||
|
# Test various operations on an unconnected SMTP object that
|
||||||
|
# should raise exceptions (at present the attempt in SMTP.send
|
||||||
|
# to reference the nonexistent 'sock' attribute of the SMTP object
|
||||||
|
# causes an AttributeError)
|
||||||
|
smtp = smtplib.SMTP()
|
||||||
|
self.assertRaises(smtplib.SMTPServerDisconnected, smtp.ehlo)
|
||||||
|
self.assertRaises(smtplib.SMTPServerDisconnected,
|
||||||
|
smtp.send, 'test msg')
|
||||||
|
|
||||||
|
def testNonnumericPort(self):
|
||||||
|
# check that non-numeric port raises socket.error
|
||||||
|
self.assertRaises(socket.error, smtplib.SMTP,
|
||||||
|
"localhost", "bogus")
|
||||||
|
self.assertRaises(socket.error, smtplib.SMTP,
|
||||||
|
"localhost:bogus")
|
||||||
|
|
||||||
|
|
||||||
# test response of client to a non-successful HELO message
|
# test response of client to a non-successful HELO message
|
||||||
class BadHELOServerTests(TestCase):
|
class BadHELOServerTests(TestCase):
|
||||||
|
|
||||||
|
@ -269,16 +259,8 @@ class BadHELOServerTests(TestCase):
|
||||||
self.evt = threading.Event()
|
self.evt = threading.Event()
|
||||||
servargs = (self.evt, b"199 no hello for you!\n")
|
servargs = (self.evt, b"199 no hello for you!\n")
|
||||||
threading.Thread(target=server, args=servargs).start()
|
threading.Thread(target=server, args=servargs).start()
|
||||||
|
self.evt.wait()
|
||||||
# wait until server thread has assigned a port number
|
self.evt.clear()
|
||||||
n = 500
|
|
||||||
while PORT is None and n > 0:
|
|
||||||
time.sleep(0.01)
|
|
||||||
n -= 1
|
|
||||||
|
|
||||||
# wait a little longer (sometimes connections are refused
|
|
||||||
# on slow machines without this additional wait)
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.evt.wait()
|
self.evt.wait()
|
||||||
|
@ -355,14 +337,8 @@ class SMTPSimTests(TestCase):
|
||||||
threading.Thread(target=debugging_server, args=serv_args).start()
|
threading.Thread(target=debugging_server, args=serv_args).start()
|
||||||
|
|
||||||
# wait until server thread has assigned a port number
|
# wait until server thread has assigned a port number
|
||||||
n = 500
|
self.serv_evt.wait()
|
||||||
while PORT is None and n > 0:
|
self.serv_evt.clear()
|
||||||
time.sleep(0.01)
|
|
||||||
n -= 1
|
|
||||||
|
|
||||||
# wait a little longer (sometimes connections are refused
|
|
||||||
# on slow machines without this additional wait)
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# indicate that the client is finished
|
# indicate that the client is finished
|
||||||
|
@ -430,6 +406,7 @@ class SMTPSimTests(TestCase):
|
||||||
|
|
||||||
def test_main(verbose=None):
|
def test_main(verbose=None):
|
||||||
test_support.run_unittest(GeneralTests, DebuggingServerTests,
|
test_support.run_unittest(GeneralTests, DebuggingServerTests,
|
||||||
|
NonConnectingTests,
|
||||||
BadHELOServerTests, SMTPSimTests)
|
BadHELOServerTests, SMTPSimTests)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
25
Lib/trace.py
25
Lib/trace.py
|
@ -53,6 +53,7 @@ import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
import token
|
import token
|
||||||
import tokenize
|
import tokenize
|
||||||
import types
|
import types
|
||||||
|
@ -94,6 +95,8 @@ Modifiers:
|
||||||
with '>>>>>> '.
|
with '>>>>>> '.
|
||||||
-s, --summary Write a brief summary on stdout for each file.
|
-s, --summary Write a brief summary on stdout for each file.
|
||||||
(Can only be used with --count or --report.)
|
(Can only be used with --count or --report.)
|
||||||
|
-g, --timing Prefix each line with the time since the program started.
|
||||||
|
Only used while tracing.
|
||||||
|
|
||||||
Filters, may be repeated multiple times:
|
Filters, may be repeated multiple times:
|
||||||
--ignore-module=<mod> Ignore the given module(s) and its submodules
|
--ignore-module=<mod> Ignore the given module(s) and its submodules
|
||||||
|
@ -431,7 +434,8 @@ def find_executable_linenos(filename):
|
||||||
|
|
||||||
class Trace:
|
class Trace:
|
||||||
def __init__(self, count=1, trace=1, countfuncs=0, countcallers=0,
|
def __init__(self, count=1, trace=1, countfuncs=0, countcallers=0,
|
||||||
ignoremods=(), ignoredirs=(), infile=None, outfile=None):
|
ignoremods=(), ignoredirs=(), infile=None, outfile=None,
|
||||||
|
timing=False):
|
||||||
"""
|
"""
|
||||||
@param count true iff it should count number of times each
|
@param count true iff it should count number of times each
|
||||||
line is executed
|
line is executed
|
||||||
|
@ -447,6 +451,7 @@ class Trace:
|
||||||
@param infile file from which to read stored counts to be
|
@param infile file from which to read stored counts to be
|
||||||
added into the results
|
added into the results
|
||||||
@param outfile file in which to write the results
|
@param outfile file in which to write the results
|
||||||
|
@param timing true iff timing information be displayed
|
||||||
"""
|
"""
|
||||||
self.infile = infile
|
self.infile = infile
|
||||||
self.outfile = outfile
|
self.outfile = outfile
|
||||||
|
@ -459,6 +464,9 @@ class Trace:
|
||||||
self._calledfuncs = {}
|
self._calledfuncs = {}
|
||||||
self._callers = {}
|
self._callers = {}
|
||||||
self._caller_cache = {}
|
self._caller_cache = {}
|
||||||
|
self.start_time = None
|
||||||
|
if timing:
|
||||||
|
self.start_time = time.time()
|
||||||
if countcallers:
|
if countcallers:
|
||||||
self.globaltrace = self.globaltrace_trackcallers
|
self.globaltrace = self.globaltrace_trackcallers
|
||||||
elif countfuncs:
|
elif countfuncs:
|
||||||
|
@ -609,6 +617,8 @@ class Trace:
|
||||||
key = filename, lineno
|
key = filename, lineno
|
||||||
self.counts[key] = self.counts.get(key, 0) + 1
|
self.counts[key] = self.counts.get(key, 0) + 1
|
||||||
|
|
||||||
|
if self.start_time:
|
||||||
|
print('%.2f' % (time.time() - self.start_time), end=' ')
|
||||||
bname = os.path.basename(filename)
|
bname = os.path.basename(filename)
|
||||||
print("%s(%d): %s" % (bname, lineno,
|
print("%s(%d): %s" % (bname, lineno,
|
||||||
linecache.getline(filename, lineno)), end=' ')
|
linecache.getline(filename, lineno)), end=' ')
|
||||||
|
@ -620,6 +630,8 @@ class Trace:
|
||||||
filename = frame.f_code.co_filename
|
filename = frame.f_code.co_filename
|
||||||
lineno = frame.f_lineno
|
lineno = frame.f_lineno
|
||||||
|
|
||||||
|
if self.start_time:
|
||||||
|
print('%.2f' % (time.time() - self.start_time), end=' ')
|
||||||
bname = os.path.basename(filename)
|
bname = os.path.basename(filename)
|
||||||
print("%s(%d): %s" % (bname, lineno,
|
print("%s(%d): %s" % (bname, lineno,
|
||||||
linecache.getline(filename, lineno)), end=' ')
|
linecache.getline(filename, lineno)), end=' ')
|
||||||
|
@ -649,13 +661,13 @@ def main(argv=None):
|
||||||
if argv is None:
|
if argv is None:
|
||||||
argv = sys.argv
|
argv = sys.argv
|
||||||
try:
|
try:
|
||||||
opts, prog_argv = getopt.getopt(argv[1:], "tcrRf:d:msC:lT",
|
opts, prog_argv = getopt.getopt(argv[1:], "tcrRf:d:msC:lTg",
|
||||||
["help", "version", "trace", "count",
|
["help", "version", "trace", "count",
|
||||||
"report", "no-report", "summary",
|
"report", "no-report", "summary",
|
||||||
"file=", "missing",
|
"file=", "missing",
|
||||||
"ignore-module=", "ignore-dir=",
|
"ignore-module=", "ignore-dir=",
|
||||||
"coverdir=", "listfuncs",
|
"coverdir=", "listfuncs",
|
||||||
"trackcalls"])
|
"trackcalls", "timing"])
|
||||||
|
|
||||||
except getopt.error as msg:
|
except getopt.error as msg:
|
||||||
sys.stderr.write("%s: %s\n" % (sys.argv[0], msg))
|
sys.stderr.write("%s: %s\n" % (sys.argv[0], msg))
|
||||||
|
@ -675,6 +687,7 @@ def main(argv=None):
|
||||||
summary = 0
|
summary = 0
|
||||||
listfuncs = False
|
listfuncs = False
|
||||||
countcallers = False
|
countcallers = False
|
||||||
|
timing = False
|
||||||
|
|
||||||
for opt, val in opts:
|
for opt, val in opts:
|
||||||
if opt == "--help":
|
if opt == "--help":
|
||||||
|
@ -693,6 +706,10 @@ def main(argv=None):
|
||||||
listfuncs = True
|
listfuncs = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if opt == "-g" or opt == "--timing":
|
||||||
|
timing = True
|
||||||
|
continue
|
||||||
|
|
||||||
if opt == "-t" or opt == "--trace":
|
if opt == "-t" or opt == "--trace":
|
||||||
trace = 1
|
trace = 1
|
||||||
continue
|
continue
|
||||||
|
@ -775,7 +792,7 @@ def main(argv=None):
|
||||||
t = Trace(count, trace, countfuncs=listfuncs,
|
t = Trace(count, trace, countfuncs=listfuncs,
|
||||||
countcallers=countcallers, ignoremods=ignore_modules,
|
countcallers=countcallers, ignoremods=ignore_modules,
|
||||||
ignoredirs=ignore_dirs, infile=counts_file,
|
ignoredirs=ignore_dirs, infile=counts_file,
|
||||||
outfile=counts_file)
|
outfile=counts_file, timing=timing)
|
||||||
try:
|
try:
|
||||||
fp = open(progname)
|
fp = open(progname)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -308,6 +308,22 @@ getargs_tuple(PyObject *self, PyObject *args)
|
||||||
return Py_BuildValue("iii", a, b, c);
|
return Py_BuildValue("iii", a, b, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test PyArg_ParseTupleAndKeywords */
|
||||||
|
static PyObject *getargs_keywords(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
{
|
||||||
|
static char *keywords[] = {"arg1","arg2","arg3","arg4","arg5", NULL};
|
||||||
|
static char *fmt="(ii)i|(i(ii))(iii)i";
|
||||||
|
int int_args[10]={-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, fmt, keywords,
|
||||||
|
&int_args[0], &int_args[1], &int_args[2], &int_args[3], &int_args[4],
|
||||||
|
&int_args[5], &int_args[6], &int_args[7], &int_args[8], &int_args[9]))
|
||||||
|
return NULL;
|
||||||
|
return Py_BuildValue("iiiiiiiiii",
|
||||||
|
int_args[0], int_args[1], int_args[2], int_args[3], int_args[4],
|
||||||
|
int_args[5], int_args[6], int_args[7], int_args[8], int_args[9]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Functions to call PyArg_ParseTuple with integer format codes,
|
/* Functions to call PyArg_ParseTuple with integer format codes,
|
||||||
and return the result.
|
and return the result.
|
||||||
*/
|
*/
|
||||||
|
@ -898,6 +914,8 @@ static PyMethodDef TestMethods[] = {
|
||||||
PyDoc_STR("This is a pretty normal docstring.")},
|
PyDoc_STR("This is a pretty normal docstring.")},
|
||||||
|
|
||||||
{"getargs_tuple", getargs_tuple, METH_VARARGS},
|
{"getargs_tuple", getargs_tuple, METH_VARARGS},
|
||||||
|
{"getargs_keywords", (PyCFunction)getargs_keywords,
|
||||||
|
METH_VARARGS|METH_KEYWORDS},
|
||||||
{"getargs_b", getargs_b, METH_VARARGS},
|
{"getargs_b", getargs_b, METH_VARARGS},
|
||||||
{"getargs_B", getargs_B, METH_VARARGS},
|
{"getargs_B", getargs_B, METH_VARARGS},
|
||||||
{"getargs_H", getargs_H, METH_VARARGS},
|
{"getargs_H", getargs_H, METH_VARARGS},
|
||||||
|
|
|
@ -1764,10 +1764,8 @@ product_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
/* create productobject structure */
|
/* create productobject structure */
|
||||||
lz = (productobject *)type->tp_alloc(type, 0);
|
lz = (productobject *)type->tp_alloc(type, 0);
|
||||||
if (lz == NULL) {
|
if (lz == NULL)
|
||||||
Py_DECREF(pools);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
|
|
||||||
lz->pools = pools;
|
lz->pools = pools;
|
||||||
lz->maxvec = maxvec;
|
lz->maxvec = maxvec;
|
||||||
|
@ -1952,6 +1950,232 @@ static PyTypeObject product_type = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* combinations object ************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
PyObject *pool; /* input converted to a tuple */
|
||||||
|
Py_ssize_t *indices; /* one index per result element */
|
||||||
|
PyObject *result; /* most recently returned result tuple */
|
||||||
|
Py_ssize_t r; /* size of result tuple */
|
||||||
|
int stopped; /* set to 1 when the combinations iterator is exhausted */
|
||||||
|
} combinationsobject;
|
||||||
|
|
||||||
|
static PyTypeObject combinations_type;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
combinations_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
combinationsobject *co;
|
||||||
|
Py_ssize_t n;
|
||||||
|
Py_ssize_t r;
|
||||||
|
PyObject *pool = NULL;
|
||||||
|
PyObject *iterable = NULL;
|
||||||
|
Py_ssize_t *indices = NULL;
|
||||||
|
Py_ssize_t i;
|
||||||
|
static char *kwargs[] = {"iterable", "r", NULL};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "On:combinations", kwargs,
|
||||||
|
&iterable, &r))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pool = PySequence_Tuple(iterable);
|
||||||
|
if (pool == NULL)
|
||||||
|
goto error;
|
||||||
|
n = PyTuple_GET_SIZE(pool);
|
||||||
|
if (r < 0) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "r must be non-negative");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (r > n) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "r cannot be bigger than the iterable");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
indices = PyMem_Malloc(r * sizeof(Py_ssize_t));
|
||||||
|
if (indices == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0 ; i<r ; i++)
|
||||||
|
indices[i] = i;
|
||||||
|
|
||||||
|
/* create combinationsobject structure */
|
||||||
|
co = (combinationsobject *)type->tp_alloc(type, 0);
|
||||||
|
if (co == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
co->pool = pool;
|
||||||
|
co->indices = indices;
|
||||||
|
co->result = NULL;
|
||||||
|
co->r = r;
|
||||||
|
co->stopped = 0;
|
||||||
|
|
||||||
|
return (PyObject *)co;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (indices != NULL)
|
||||||
|
PyMem_Free(indices);
|
||||||
|
Py_XDECREF(pool);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
combinations_dealloc(combinationsobject *co)
|
||||||
|
{
|
||||||
|
PyObject_GC_UnTrack(co);
|
||||||
|
Py_XDECREF(co->pool);
|
||||||
|
Py_XDECREF(co->result);
|
||||||
|
PyMem_Free(co->indices);
|
||||||
|
Py_TYPE(co)->tp_free(co);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
combinations_traverse(combinationsobject *co, visitproc visit, void *arg)
|
||||||
|
{
|
||||||
|
Py_VISIT(co->pool);
|
||||||
|
Py_VISIT(co->result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
combinations_next(combinationsobject *co)
|
||||||
|
{
|
||||||
|
PyObject *elem;
|
||||||
|
PyObject *oldelem;
|
||||||
|
PyObject *pool = co->pool;
|
||||||
|
Py_ssize_t *indices = co->indices;
|
||||||
|
PyObject *result = co->result;
|
||||||
|
Py_ssize_t n = PyTuple_GET_SIZE(pool);
|
||||||
|
Py_ssize_t r = co->r;
|
||||||
|
Py_ssize_t i, j, index;
|
||||||
|
|
||||||
|
if (co->stopped)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (result == NULL) {
|
||||||
|
/* On the first pass, initialize result tuple using the indices */
|
||||||
|
result = PyTuple_New(r);
|
||||||
|
if (result == NULL)
|
||||||
|
goto empty;
|
||||||
|
co->result = result;
|
||||||
|
for (i=0; i<r ; i++) {
|
||||||
|
index = indices[i];
|
||||||
|
elem = PyTuple_GET_ITEM(pool, index);
|
||||||
|
Py_INCREF(elem);
|
||||||
|
PyTuple_SET_ITEM(result, i, elem);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Copy the previous result tuple or re-use it if available */
|
||||||
|
if (Py_REFCNT(result) > 1) {
|
||||||
|
PyObject *old_result = result;
|
||||||
|
result = PyTuple_New(r);
|
||||||
|
if (result == NULL)
|
||||||
|
goto empty;
|
||||||
|
co->result = result;
|
||||||
|
for (i=0; i<r ; i++) {
|
||||||
|
elem = PyTuple_GET_ITEM(old_result, i);
|
||||||
|
Py_INCREF(elem);
|
||||||
|
PyTuple_SET_ITEM(result, i, elem);
|
||||||
|
}
|
||||||
|
Py_DECREF(old_result);
|
||||||
|
}
|
||||||
|
/* Now, we've got the only copy so we can update it in-place
|
||||||
|
* CPython's empty tuple is a singleton and cached in
|
||||||
|
* PyTuple's freelist.
|
||||||
|
*/
|
||||||
|
assert(r == 0 || Py_REFCNT(result) == 1);
|
||||||
|
|
||||||
|
/* Scan indices right-to-left until finding one that is not
|
||||||
|
at its maximum (i + n - r). */
|
||||||
|
for (i=r-1 ; i >= 0 && indices[i] == i+n-r ; i--)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* If i is negative, then the indices are all at
|
||||||
|
their maximum value and we're done. */
|
||||||
|
if (i < 0)
|
||||||
|
goto empty;
|
||||||
|
|
||||||
|
/* Increment the current index which we know is not at its
|
||||||
|
maximum. Then move back to the right setting each index
|
||||||
|
to its lowest possible value (one higher than the index
|
||||||
|
to its left -- this maintains the sort order invariant). */
|
||||||
|
indices[i]++;
|
||||||
|
for (j=i+1 ; j<r ; j++)
|
||||||
|
indices[j] = indices[j-1] + 1;
|
||||||
|
|
||||||
|
/* Update the result tuple for the new indices
|
||||||
|
starting with i, the leftmost index that changed */
|
||||||
|
for ( ; i<r ; i++) {
|
||||||
|
index = indices[i];
|
||||||
|
elem = PyTuple_GET_ITEM(pool, index);
|
||||||
|
Py_INCREF(elem);
|
||||||
|
oldelem = PyTuple_GET_ITEM(result, i);
|
||||||
|
PyTuple_SET_ITEM(result, i, elem);
|
||||||
|
Py_DECREF(oldelem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(result);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
empty:
|
||||||
|
co->stopped = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(combinations_doc,
|
||||||
|
"combinations(iterables) --> combinations object\n\
|
||||||
|
\n\
|
||||||
|
Return successive r-length combinations of elements in the iterable.\n\n\
|
||||||
|
combinations(range(4), 3) --> (0,1,2), (0,1,3), (0,2,3), (1,2,3)");
|
||||||
|
|
||||||
|
static PyTypeObject combinations_type = {
|
||||||
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
|
"itertools.combinations", /* tp_name */
|
||||||
|
sizeof(combinationsobject), /* tp_basicsize */
|
||||||
|
0, /* tp_itemsize */
|
||||||
|
/* methods */
|
||||||
|
(destructor)combinations_dealloc, /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
0, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
0, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||||
|
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
|
combinations_doc, /* tp_doc */
|
||||||
|
(traverseproc)combinations_traverse, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
PyObject_SelfIter, /* tp_iter */
|
||||||
|
(iternextfunc)combinations_next, /* tp_iternext */
|
||||||
|
0, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
0, /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
combinations_new, /* tp_new */
|
||||||
|
PyObject_GC_Del, /* tp_free */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* ifilter object ************************************************************/
|
/* ifilter object ************************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -2978,6 +3202,7 @@ inititertools(void)
|
||||||
PyObject *m;
|
PyObject *m;
|
||||||
char *name;
|
char *name;
|
||||||
PyTypeObject *typelist[] = {
|
PyTypeObject *typelist[] = {
|
||||||
|
&combinations_type,
|
||||||
&cycle_type,
|
&cycle_type,
|
||||||
&dropwhile_type,
|
&dropwhile_type,
|
||||||
&takewhile_type,
|
&takewhile_type,
|
||||||
|
|
257
Python/getargs.c
257
Python/getargs.c
|
@ -1401,6 +1401,7 @@ _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
|
vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
|
||||||
|
@ -1408,13 +1409,10 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
|
||||||
{
|
{
|
||||||
char msgbuf[512];
|
char msgbuf[512];
|
||||||
int levels[32];
|
int levels[32];
|
||||||
const char *fname, *message;
|
const char *fname, *msg, *custom_msg, *keyword;
|
||||||
int min, max;
|
int min = INT_MAX;
|
||||||
const char *formatsave;
|
|
||||||
int i, len, nargs, nkeywords;
|
int i, len, nargs, nkeywords;
|
||||||
const char *msg;
|
PyObject *freelist = NULL, *current_arg;
|
||||||
char **p;
|
|
||||||
PyObject *freelist = NULL;
|
|
||||||
|
|
||||||
assert(args != NULL && PyTuple_Check(args));
|
assert(args != NULL && PyTuple_Check(args));
|
||||||
assert(keywords == NULL || PyDict_Check(keywords));
|
assert(keywords == NULL || PyDict_Check(keywords));
|
||||||
|
@ -1422,166 +1420,106 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
|
||||||
assert(kwlist != NULL);
|
assert(kwlist != NULL);
|
||||||
assert(p_va != NULL);
|
assert(p_va != NULL);
|
||||||
|
|
||||||
/* Search the format:
|
/* grab the function name or custom error msg first (mutually exclusive) */
|
||||||
message <- error msg, if any (else NULL).
|
fname = strchr(format, ':');
|
||||||
fname <- routine name, if any (else NULL).
|
if (fname) {
|
||||||
min <- # of required arguments, or -1 if all are required.
|
fname++;
|
||||||
max <- most arguments (required + optional).
|
custom_msg = NULL;
|
||||||
Check that kwlist has a non-NULL entry for each arg.
|
|
||||||
Raise error if a tuple arg spec is found.
|
|
||||||
*/
|
|
||||||
fname = message = NULL;
|
|
||||||
formatsave = format;
|
|
||||||
p = kwlist;
|
|
||||||
min = -1;
|
|
||||||
max = 0;
|
|
||||||
while ((i = *format++) != '\0') {
|
|
||||||
if (isalpha(Py_CHARMASK(i)) && i != 'e') {
|
|
||||||
max++;
|
|
||||||
if (*p == NULL) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
|
||||||
"more argument specifiers than "
|
|
||||||
"keyword list entries");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
p++;
|
else {
|
||||||
}
|
custom_msg = strchr(format,';');
|
||||||
else if (i == '|')
|
if (custom_msg)
|
||||||
min = max;
|
custom_msg++;
|
||||||
else if (i == ':') {
|
|
||||||
fname = format;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (i == ';') {
|
|
||||||
message = format;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (i == '(') {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
|
||||||
"tuple found in format when using keyword "
|
|
||||||
"arguments");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
format = formatsave;
|
|
||||||
if (*p != NULL) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
|
||||||
"more keyword list entries than "
|
|
||||||
"argument specifiers");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (min < 0) {
|
|
||||||
/* All arguments are required. */
|
|
||||||
min = max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* scan kwlist and get greatest possible nbr of args */
|
||||||
|
for (len=0; kwlist[len]; len++)
|
||||||
|
continue;
|
||||||
|
|
||||||
nargs = PyTuple_GET_SIZE(args);
|
nargs = PyTuple_GET_SIZE(args);
|
||||||
nkeywords = keywords == NULL ? 0 : PyDict_Size(keywords);
|
nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords);
|
||||||
|
if (nargs + nkeywords > len) {
|
||||||
/* make sure there are no duplicate values for an argument;
|
PyErr_Format(PyExc_TypeError, "%s%s takes at most %d "
|
||||||
its not clear when to use the term "keyword argument vs.
|
"argument%s (%d given)",
|
||||||
keyword parameter in messages */
|
(fname == NULL) ? "function" : fname,
|
||||||
if (nkeywords > 0) {
|
(fname == NULL) ? "" : "()",
|
||||||
for (i = 0; i < nargs; i++) {
|
len,
|
||||||
const char *thiskw = kwlist[i];
|
(len == 1) ? "" : "s",
|
||||||
if (thiskw == NULL)
|
nargs + nkeywords);
|
||||||
break;
|
|
||||||
if (PyDict_GetItemString(keywords, thiskw)) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"keyword parameter '%s' was given "
|
|
||||||
"by position and by name",
|
|
||||||
thiskw);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (PyErr_Occurred())
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* required arguments missing from args can be supplied by keyword
|
|
||||||
arguments; set len to the number of positional arguments, and,
|
|
||||||
if that's less than the minimum required, add in the number of
|
|
||||||
required arguments that are supplied by keywords */
|
|
||||||
len = nargs;
|
|
||||||
if (nkeywords > 0 && nargs < min) {
|
|
||||||
for (i = nargs; i < min; i++) {
|
|
||||||
if (PyDict_GetItemString(keywords, kwlist[i]))
|
|
||||||
len++;
|
|
||||||
else if (PyErr_Occurred())
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure we got an acceptable number of arguments; the message
|
|
||||||
is a little confusing with keywords since keyword arguments
|
|
||||||
which are supplied, but don't match the required arguments
|
|
||||||
are not included in the "%d given" part of the message
|
|
||||||
XXX and this isn't a bug!? */
|
|
||||||
if (len < min || max < len) {
|
|
||||||
if (message == NULL) {
|
|
||||||
PyOS_snprintf(msgbuf, sizeof(msgbuf),
|
|
||||||
"%.200s%s takes %s %d argument%s "
|
|
||||||
"(%d given)",
|
|
||||||
fname==NULL ? "function" : fname,
|
|
||||||
fname==NULL ? "" : "()",
|
|
||||||
min==max ? "exactly"
|
|
||||||
: len < min ? "at least" : "at most",
|
|
||||||
len < min ? min : max,
|
|
||||||
(len < min ? min : max) == 1 ? "" : "s",
|
|
||||||
len);
|
|
||||||
message = msgbuf;
|
|
||||||
}
|
|
||||||
PyErr_SetString(PyExc_TypeError, message);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert the positional arguments */
|
/* convert tuple args and keyword args in same loop, using kwlist to drive process */
|
||||||
for (i = 0; i < nargs; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
if (*format == '|')
|
keyword = kwlist[i];
|
||||||
|
if (*format == '|') {
|
||||||
|
min = i;
|
||||||
format++;
|
format++;
|
||||||
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
|
}
|
||||||
flags, levels, msgbuf, sizeof(msgbuf),
|
if (IS_END_OF_FORMAT(*format)) {
|
||||||
&freelist);
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
if (msg) {
|
"More keyword list entries (%d) than "
|
||||||
seterror(i+1, msg, levels, fname, message);
|
"format specifiers (%d)", len, i);
|
||||||
|
return cleanreturn(0, freelist);
|
||||||
|
}
|
||||||
|
current_arg = NULL;
|
||||||
|
if (nkeywords) {
|
||||||
|
current_arg = PyDict_GetItemString(keywords, keyword);
|
||||||
|
}
|
||||||
|
if (current_arg) {
|
||||||
|
--nkeywords;
|
||||||
|
if (i < nargs) {
|
||||||
|
/* arg present in tuple and in dict */
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"Argument given by name ('%s') "
|
||||||
|
"and position (%d)",
|
||||||
|
keyword, i+1);
|
||||||
return cleanreturn(0, freelist);
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (nkeywords && PyErr_Occurred())
|
||||||
|
return cleanreturn(0, freelist);
|
||||||
|
else if (i < nargs)
|
||||||
|
current_arg = PyTuple_GET_ITEM(args, i);
|
||||||
|
|
||||||
/* handle no keyword parameters in call */
|
if (current_arg) {
|
||||||
if (nkeywords == 0)
|
msg = convertitem(current_arg, &format, p_va, flags,
|
||||||
|
levels, msgbuf, sizeof(msgbuf), &freelist);
|
||||||
|
if (msg) {
|
||||||
|
seterror(i+1, msg, levels, fname, custom_msg);
|
||||||
|
return cleanreturn(0, freelist);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < min) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "Required argument "
|
||||||
|
"'%s' (pos %d) not found",
|
||||||
|
keyword, i+1);
|
||||||
|
return cleanreturn(0, freelist);
|
||||||
|
}
|
||||||
|
/* current code reports success when all required args
|
||||||
|
* fulfilled and no keyword args left, with no further
|
||||||
|
* validation. XXX Maybe skip this in debug build ?
|
||||||
|
*/
|
||||||
|
if (!nkeywords)
|
||||||
return cleanreturn(1, freelist);
|
return cleanreturn(1, freelist);
|
||||||
|
|
||||||
/* convert the keyword arguments; this uses the format
|
/* We are into optional args, skip thru to any remaining
|
||||||
string where it was left after processing args */
|
* keyword args */
|
||||||
for (i = nargs; i < max; i++) {
|
|
||||||
PyObject *item;
|
|
||||||
if (*format == '|')
|
|
||||||
format++;
|
|
||||||
item = PyDict_GetItemString(keywords, kwlist[i]);
|
|
||||||
if (item != NULL) {
|
|
||||||
Py_INCREF(item);
|
|
||||||
msg = convertitem(item, &format, p_va, flags, levels,
|
|
||||||
msgbuf, sizeof(msgbuf), &freelist);
|
|
||||||
Py_DECREF(item);
|
|
||||||
if (msg) {
|
|
||||||
seterror(i+1, msg, levels, fname, message);
|
|
||||||
return cleanreturn(0, freelist);
|
|
||||||
}
|
|
||||||
--nkeywords;
|
|
||||||
if (nkeywords == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (PyErr_Occurred())
|
|
||||||
return cleanreturn(0, freelist);
|
|
||||||
else {
|
|
||||||
msg = skipitem(&format, p_va, flags);
|
msg = skipitem(&format, p_va, flags);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
levels[0] = 0;
|
PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg,
|
||||||
seterror(i+1, msg, levels, fname, message);
|
format);
|
||||||
return cleanreturn(0, freelist);
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IS_END_OF_FORMAT(*format)) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"more argument specifiers than keyword list entries "
|
||||||
|
"(remaining format:'%s')", format);
|
||||||
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure there are no extraneous keyword arguments */
|
/* make sure there are no extraneous keyword arguments */
|
||||||
|
@ -1597,7 +1535,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
|
||||||
return cleanreturn(0, freelist);
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
ks = PyUnicode_AsString(key);
|
ks = PyUnicode_AsString(key);
|
||||||
for (i = 0; i < max; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
if (!strcmp(ks, kwlist[i])) {
|
if (!strcmp(ks, kwlist[i])) {
|
||||||
match = 1;
|
match = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -1726,15 +1664,32 @@ skipitem(const char **p_format, va_list *p_va, int flags)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case '(': /* bypass tuple, not handled at all previously */
|
||||||
|
{
|
||||||
|
char *msg;
|
||||||
|
for (;;) {
|
||||||
|
if (*format==')')
|
||||||
|
break;
|
||||||
|
if (IS_END_OF_FORMAT(*format))
|
||||||
|
return "Unmatched left paren in format "
|
||||||
|
"string";
|
||||||
|
msg = skipitem(&format, p_va, flags);
|
||||||
|
if (msg)
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ')':
|
||||||
|
return "Unmatched right paren in format string";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err:
|
err:
|
||||||
return "impossible<bad format char>";
|
return "impossible<bad format char>";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The "(...)" format code for tuples is not handled here because
|
|
||||||
* it is not allowed with keyword args. */
|
|
||||||
|
|
||||||
*p_format = format;
|
*p_format = format;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue