diff --git a/Doc/tools/roman.py b/Doc/tools/roman.py new file mode 100644 index 00000000000..33f6db7ed3a --- /dev/null +++ b/Doc/tools/roman.py @@ -0,0 +1,80 @@ +"""Convert to and from Roman numerals""" + +__author__ = "Mark Pilgrim (f8dy@diveintopython.org)" +__version__ = "1.4" +__date__ = "8 August 2001" +__copyright__ = """Copyright (c) 2001 Mark Pilgrim + +This program is part of "Dive Into Python", a free Python tutorial for +experienced programmers. Visit http://diveintopython.org/ for the +latest version. + +This program is free software; you can redistribute it and/or modify +it under the terms of the Python 2.1.1 license, available at +http://www.python.org/2.1.1/license.html +""" + +import re + +#Define exceptions +class RomanError(Exception): pass +class OutOfRangeError(RomanError): pass +class NotIntegerError(RomanError): pass +class InvalidRomanNumeralError(RomanError): pass + +#Define digit mapping +romanNumeralMap = (('M', 1000), + ('CM', 900), + ('D', 500), + ('CD', 400), + ('C', 100), + ('XC', 90), + ('L', 50), + ('XL', 40), + ('X', 10), + ('IX', 9), + ('V', 5), + ('IV', 4), + ('I', 1)) + +def toRoman(n): + """convert integer to Roman numeral""" + if not (0 < n < 5000): + raise OutOfRangeError, "number out of range (must be 1..4999)" + if int(n) <> n: + raise NotIntegerError, "decimals can not be converted" + + result = "" + for numeral, integer in romanNumeralMap: + while n >= integer: + result += numeral + n -= integer + return result + +#Define pattern to detect valid Roman numerals +romanNumeralPattern = re.compile(""" + ^ # beginning of string + M{0,4} # thousands - 0 to 4 M's + (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's), + # or 500-800 (D, followed by 0 to 3 C's) + (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's), + # or 50-80 (L, followed by 0 to 3 X's) + (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's), + # or 5-8 (V, followed by 0 to 3 I's) + $ # end of string + """ ,re.VERBOSE) + +def fromRoman(s): + """convert Roman numeral to integer""" + if not s: + raise InvalidRomanNumeralError, 'Input can not be blank' + if not romanNumeralPattern.search(s): + raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s + + result = 0 + index = 0 + for numeral, integer in romanNumeralMap: + while s[index:index+len(numeral)] == numeral: + result += integer + index += len(numeral) + return result diff --git a/Lib/decimal.py b/Lib/decimal.py index 17d67d541d0..cca0a442174 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -612,7 +612,8 @@ class Decimal(object): except ValueError: self._is_special = True self._sign, self._int, self._exp = \ - context._raise_error(ConversionSyntax) + context._raise_error(ConversionSyntax, + "Invalid literal for Decimal: %r" % value) return self raise TypeError("Cannot convert %r to Decimal" % value) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index ed1d6dc0338..90f6ae7d8b9 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -5,8 +5,7 @@ import sys import unittest import pickle -from test.test_support import (TESTFN, unlink, run_unittest, - guard_warnings_filter) +from test.test_support import TESTFN, unlink, run_unittest # XXX This is not really enough, each *operation* should be tested! diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py index 884d05217dc..32039045f99 100644 --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -1,4 +1,4 @@ -from test.test_support import TESTFN, run_unittest, guard_warnings_filter +from test.test_support import TESTFN, run_unittest, catch_warning import unittest import os @@ -151,7 +151,7 @@ class ImportTest(unittest.TestCase): self.assert_(y is test.test_support, y.__name__) def test_import_initless_directory_warning(self): - with guard_warnings_filter(): + with catch_warning(): # Just a random non-package directory we always expect to be # somewhere in sys.path... warnings.simplefilter('error', ImportWarning) diff --git a/Lib/test/test_macostools.py b/Lib/test/test_macostools.py index 40b690a1f6a..eea3601cf30 100644 --- a/Lib/test/test_macostools.py +++ b/Lib/test/test_macostools.py @@ -52,7 +52,7 @@ class TestMacostools(unittest.TestCase): def test_touched(self): # This really only tests that nothing unforeseen happens. import warnings - with test_support.guard_warnings_filter(): + with test_support.catch_warning(): warnings.filterwarnings('ignore', 'macostools.touched*', DeprecationWarning) macostools.touched(test_support.TESTFN) diff --git a/Lib/test/test_pep352.py b/Lib/test/test_pep352.py index dc47737feb3..ddeee1a1b7f 100644 --- a/Lib/test/test_pep352.py +++ b/Lib/test/test_pep352.py @@ -1,7 +1,7 @@ import unittest import __builtin__ import warnings -from test.test_support import run_unittest, guard_warnings_filter +from test.test_support import run_unittest import os from platform import system as platform_system diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 43273d83439..19897861cbd 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -182,7 +182,7 @@ class WichmannHill_TestBasicOps(TestBasicOps): def test_bigrand(self): # Verify warnings are raised when randrange is too large for random() - with test_support.guard_warnings_filter(): + with test_support.catch_warning(): warnings.filterwarnings("error", "Underlying random") self.assertRaises(UserWarning, self.gen.randrange, 2**60) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index f14ff49488b..f166188fb48 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1,7 +1,7 @@ import sys sys.path = ['.'] + sys.path -from test.test_support import verbose, run_unittest, guard_warnings_filter +from test.test_support import verbose, run_unittest, catch_warning import re from re import Scanner import sys, os, traceback @@ -414,7 +414,7 @@ class ReTests(unittest.TestCase): self.pickle_test(pickle) # old pickles expect the _compile() reconstructor in sre module import warnings - with guard_warnings_filter(): + with catch_warning(): warnings.filterwarnings("ignore", "The sre module is deprecated", DeprecationWarning) from sre import _compile diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 69057fc9f9b..d3b78570a1f 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -50,7 +50,7 @@ def any_err(func, *args): def with_warning_restore(func): def _with_warning_restore(*args, **kw): - with test.test_support.guard_warnings_filter(): + with test.test_support.catch_warning(): # Grrr, we need this function to warn every time. Without removing # the warningregistry, running test_tarfile then test_struct would fail # on 64-bit platforms. diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py index 6afc63bbe67..ed2f14d2ea4 100644 --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -1,10 +1,10 @@ """Do a minimal test of all the modules that aren't otherwise tested.""" -from test.test_support import guard_warnings_filter +from test.test_support import catch_warning import sys import warnings -with guard_warnings_filter(): +with catch_warning(): from test.test_support import verbose import BaseHTTPServer diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 698507f2531..fa4c3ef2515 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -261,14 +261,6 @@ def open_urlresource(url): fn, _ = urllib.urlretrieve(url, filename) return open(fn) -@contextlib.contextmanager -def guard_warnings_filter(): - """Guard the warnings filter from being permanently changed.""" - original_filters = warnings.filters[:] - try: - yield - finally: - warnings.filters = original_filters class WarningMessage(object): "Holds the result of the latest showwarning() call" @@ -292,7 +284,7 @@ def catch_warning(): Use like this: - with catch_warning as w: + with catch_warning() as w: warnings.warn("foo") assert str(w.message) == "foo" """ diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index 5768a684606..54d5dd2dbdb 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -61,7 +61,7 @@ class TestModule(unittest.TestCase): def test_options(self): # Uses the private _setoption() function to test the parsing # of command-line warning arguments - with test_support.guard_warnings_filter(): + with test_support.catch_warning(): self.assertRaises(warnings._OptionError, warnings._setoption, '1:2:3:4:5:6') self.assertRaises(warnings._OptionError, diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 75a439ff5e0..4a15de53a55 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -4,6 +4,8 @@ import sys import time import unittest import xmlrpclib +import SimpleXMLRPCServer +import threading from test import test_support alist = [{'astring': 'foo@bar.baz.spam', @@ -239,10 +241,108 @@ class BinaryTestCase(unittest.TestCase): self.assertEqual(str(t2), d) -def test_main(): - test_support.run_unittest(XMLRPCTestCase, HelperTestCase, - DateTimeTestCase, BinaryTestCase, FaultTestCase) +PORT = None +def http_server(evt, numrequests): + class TestInstanceClass: + def div(self, x, y): + '''This is the div function''' + return x // y + + + serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0), + logRequests=False, bind_and_activate=False) + + try: + serv.socket.settimeout(3) + serv.server_bind() + global PORT + PORT = serv.socket.getsockname()[1] + serv.server_activate() + serv.register_introspection_functions() + serv.register_multicall_functions() + serv.register_function(pow) + serv.register_function(lambda x,y: x+y, 'add') + serv.register_instance(TestInstanceClass()) + + # handle up to 'numrequests' requests + while numrequests > 0: + serv.handle_request() + numrequests -= 1 + + except socket.timeout: + pass + finally: + serv.socket.close() + PORT = None + evt.set() + + +class HTTPTestCase(unittest.TestCase): + def setUp(self): + self.evt = threading.Event() + # start server thread to handle just one request + threading.Thread(target=http_server, args=(self.evt,2)).start() + + # wait for port to be assigned to server + n = 1000 + while n > 0 and PORT is None: + time.sleep(0.001) + n -= 1 + + time.sleep(0.5) + + def tearDown(self): + # wait on the server thread to terminate + self.evt.wait() + + def test_simple1(self): + p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) + self.assertEqual(p.pow(6,8), 6**8) + + def test_introspection1(self): + p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) + meth = p.system.listMethods() + expected_methods = set(['pow', 'div', 'add', 'system.listMethods', + 'system.methodHelp', 'system.methodSignature', 'system.multicall']) + self.assertEqual(set(meth), expected_methods) + + def test_introspection2(self): + p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) + divhelp = p.system.methodHelp('div') + self.assertEqual(divhelp, 'This is the div function') + + def test_introspection3(self): + # the SimpleXMLRPCServer doesn't support signatures, but + # at least check that we can try + p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) + divsig = p.system.methodSignature('div') + self.assertEqual(divsig, 'signatures not supported') + + def test_multicall(self): + p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT) + multicall = xmlrpclib.MultiCall(p) + multicall.add(2,3) + multicall.pow(6,8) + multicall.div(127,42) + add_result, pow_result, div_result = multicall() + self.assertEqual(add_result, 2+3) + self.assertEqual(pow_result, 6**8) + self.assertEqual(div_result, 127//42) + + +def test_main(): + xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase, + BinaryTestCase, FaultTestCase] + + # The test cases against a SimpleXMLRPCServer raise a socket error + # 10035 (WSAEWOULDBLOCK) in the server thread handle_request call when + # run on Windows. This only happens on the first test to run, but it + # fails every time and so these tests are skipped on win32 platforms. + if sys.platform != 'win32': + xmlrpc_tests.append(HTTPTestCase) + + test_support.run_unittest(*xmlrpc_tests) if __name__ == "__main__": test_main() diff --git a/Misc/build.sh b/Misc/build.sh index 2c0665fe685..b08a5d4948a 100755 --- a/Misc/build.sh +++ b/Misc/build.sh @@ -220,7 +220,6 @@ start=`current_time` # after the first release of 2.6a1 or 3.0a1. At that point, it will be clear # if there will be a similar problem with the new doc system. -# At that point, it should be clear if this code is needed or not. # Doc/commontex/boilerplate.tex is expected to always have an outstanding # modification for the date. When a release is cut, a conflict occurs. # This allows us to detect this problem and not try to build the docs diff --git a/Misc/developers.txt b/Misc/developers.txt index ae85ef562be..db132ae7aa9 100644 --- a/Misc/developers.txt +++ b/Misc/developers.txt @@ -17,13 +17,14 @@ the format to accommodate documentation needs as they arise. Permissions History ------------------- -- Senthil Kumaran was given SVN access on June 16 2007 - by MvL, for his Summer-of-Code project, mentored by - Skip Montanaro. +- Jeffrey Yasskin was given SVN access on 9 August 2007 by NCN, + for his work on PEPs and other general patches. -- Alexandre Vassalotti was given SVN access on May 21 2007 - by MvL, for his Summer-of-Code project, mentored by - Brett Cannon. +- Senthil Kumaran was given SVN access on 16 June 2007 by MvL, + for his Summer-of-Code project, mentored by Skip Montanaro. + +- Alexandre Vassalotti was given SVN access on 21 May 2007 by MvL, + for his Summer-of-Code project, mentored by Brett Cannon. - Travis Oliphant was given SVN access on 17 Apr 2007 by MvL, for implementing the extended buffer protocol. diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py index 93c6ba7f440..adf470f90a9 100644 --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -104,6 +104,7 @@ msvcr71_uuid = "{8666C8DD-D0B4-4B42-928E-A69E32FA5D4D}" pythondll_uuid = { "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}", "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}" + "26":"{34ebecac-f046-4e1c-b0e3-9bac3cdaacfa}", } [major+minor] # Build the mingw import library, libpythonXY.a